불변 Object Storage 를 사용하여 버킷 보호
불변 오브젝트 스토리지는 전자 레코드를 보존하고 데이터 무결성을 유지합니다. 보존 정책은 WORM(Write-Once-Read-Many), 삭제 불가능, 재작성 불가능 방식으로 데이터가 저장되도록 합니다. 이 정책은 보존 기간이 종료되고 모든 법적 보존(legal hold)이 해제될 때까지 적용됩니다.
이 기능은 현재 Satellite 의 경우 Object Storage 에서 지원되지 않습니다. 자세히 보기
정책은 보존 기간이 끝날 때까지 적용되며 보존 기간이 만료될 때까지 변경할 수 없습니다. IBM Cloud Object Storage 는 대부분의 작업에 S3 API를 사용하지만, 일부 용어는 공유할 수 있지만 보존 정책을 구성하는 데 사용되는 API는 S3 API와 동일하지 않습니다. 이 문서를 주의 깊게 읽고 조직의 어떤 사용자도 IBM Cloud 관리자도 삭제할 수 없는 개체를 만들지 못하도록 하세요.
다음 산업의 조직 외에도 해당 환경에서 장기 데이터 보존이 필요한 사용자가 이 기능을 사용할 수 있습니다.
- 금융
- 의료
- 미디어 컨텐츠 아카이브
- 오브젝트 또는 문서에 대한 권한 있는 수정 또는 삭제를 방지하려는 모든 사용자
보존 정책은 증권 중개인 트랜잭션과 같은 금융 레코드 관리를 처리하는 조직에서도 사용 가능하며, 재작성이 불가능하고 삭제 불가능한 형식으로 오브젝트를 저장해야 할 수 있습니다.
불변 오브젝트 스토리지는 특정 지역에서만 사용 가능합니다. 세부사항은 통합 서비스를 참조하십시오. 또한 표준 가격 플랜도 필요합니다. 세부사항은 가격을 참조하십시오.
보존 정책이 있는 버킷에서 Aspera 고속 전송을 사용할 수 없습니다.
용어 및 사용법
보존 기간
개체가 IBM Cloud Object Storage 버킷에 저장되어야 하는 기간입니다.
보존 정책
보존 정책은 IBM Cloud Object Storage 버킷 수준에서 활성화됩니다. 최소, 최대 및 기본 보존 기간은 이 정책으로 정의되며 버킷의 모든 오브젝트에 적용됩니다.
최소 보존 기간은 오브젝트가 버킷에서 수정되지 않은 상태로 유지되어야 하는 최소 지속 시간입니다.
최대 보존 기간은 오브젝트가 버킷에서 수정되지 않은 상태로 유지될 수 있는 최대 지속 시간입니다.
사용자 정의 보존 기간을 지정하지 않고 오브젝트를 버킷에 저장하는 경우 기본 보존 기간이 사용됩니다. 최소 보존 기간은 기본 보존 기간보다 짧거나 같아야 하며, 최대 보존 기간보다 짧거나 같아야 합니다.
개체에 대해 최대 99년의 보존 기간을 지정할 수 있습니다.
버킷에 대한 보존 정책을 작성하려면 관리자 역할이 필요합니다. 세부사항은 버킷 권한을 참조하십시오.
법적 보존
보존 기간이 만료된 후 특정 오브젝트가 수정되지 않도록 해야 할 수 있습니다. 예를 들어, 원래 설정된 보존 기간을 지나 연장된 지속 기간 동안 레코드가 액세스 가능해야 할 수 있는 불완전 법적 검토가 있습니다. 그러면 오브젝트 레벨에서 법적 보존 플래그를 적용할 수 있습니다. 법적 보존(legal hold)은 첫 업로드 중에, 또는 오브젝트가 기록된 후 적용될 수 있습니다. 참고: 오브젝트마다 최대 100개의 법적 보존을 적용할 수 있습니다.
무기한 보존
사용자는 새 보존 기간이 적용될 때까지 오브젝트가 무기한 저장되도록 설정할 수 있습니다. 이는 오브젝트별 레벨에서 설정됩니다.
무기한 보존을 사용하여 보존된 객체는 해당 객체의 보존이 -1 에서 양의 유한 값으로 변환될 때까지 완전히 불변하지 않습니다. -1 (무기한 보존)으로 작성된 개체는 DELETE object 또는 덮어쓰기 요청으로 삭제할 수 없지만, 보존 기간을 -1 에서 현재 날짜/시간으로 업데이트하면 개체를 즉시 삭제할 수 있습니다.
사용자는 스토리지 요구 사항에 대한 실행 가능성을 평가할 때 이 동작을 고려해야 합니다. 무기한 보존의 일반적인 사용 사례는 이벤트 기반 보존 에 설명되어 있습니다. 이벤트 기반 보존을 사용하거나 사용하려는 경우, 사용자가 객체를 시스템에 처음 업로드할 때 보존이 필요한지 확실하지 않은 경우 Immutable Object Storage을 사용하면 객체에 대해 무기한 보존을 설정할 수 있습니다. 무기한으로 설정하면 사용자 애플리케이션은 특정 이벤트가 발생했을 때 개체 보존을 유한한 값으로 변경할 수 있습니다.
예시 회사에서 직원이 퇴사한 후 3년 동안 직원 기록을 보관하는 정책을 가지고 있다고 가정합니다.
- 직원이 입사하여 회사에서 업무를 시작하면 해당 직원과 관련된 기록은 무기한 보관할 수 있습니다.
- 그리고 같은 직원이 퇴사하면 무기한 재직 기간은 회사 정책에 따라 현재 시점부터 3년이라는 유한한 값으로 전환됩니다.
사용자 또는 서드파티 애플리케이션이 SDK 또는 REST API를 사용하여 무기한에서 한정된 보존으로 보존 기간을 변경할 수 있습니다.
버킷 소유자와 허용된 사용자는 현재 무기한 보존을 사용하여 보존 중인 개체에 대해 구성할 수 있는 새 보존을 제한할 수 있습니다. 이는 버킷 보존 최소 및 최대 허용 값을 활용하여 수행됩니다. 이렇게 하면 무기한 보존으로 보존된 개체의 보존 기간이 현재 시간으로 업데이트되어 즉시 삭제할 수 있는 경우를 방지할 수 있습니다.
이벤트 기반 보존
불변 오브젝트 스토리지를 사용하면 사용자가 보존 기간의 최종 지속 기간에 대해 확신이 없거나 이벤트 기반 보존을 사용하려는 경우 오브젝트에 대한 무기한 보존을 설정할 수 있습니다. 무기한으로 설정되면 사용자 애플리케이션이 나중에 오브젝트 보존을 한정된 값으로 변경할 수 있습니다. 예를 들어, 회사에 직원이 퇴사한 후 3년 동안 직원 레코드를 보존하는 정책이 있습니다. 직원이 회사에 들어오면 이 직원과 연관된 레코드가 무기한 보존될 수 있습니다. 직원이 퇴사하면 무기한 보존이 회사 정책에 정의된 대로 현재 시간부터 3년이라는 한정된 값으로 변환됩니다. 그러면 보존 기간 변경 후 오브젝트는 3년 동안 보호됩니다. 사용자 또는 서드파티 애플리케이션이 SDK 또는 REST API를 사용하여 무기한에서 한정된 보존으로 보존 기간을 변경할 수 있습니다.
영구 보존
영구 보존을 사용하면 누구도 데이터를 삭제할 수 없습니다. 영구 데이터 스토리지에 대한 강력한 규정 또는 규정 준수가 필요하지 않으면 문서를 주의깊게 읽고 영구 보존을 사용하지 마십시오.
영구 보존은 보존 정책이 활성화된 IBM Cloud Object Storage 버킷 수준에서만 활성화할 수 있으며, 사용자는 오브젝트 업로드 중에 영구 보존 기간 옵션을 선택할 수 있습니다. 사용으로 설정되면 이 프로세스는 되돌릴 수 없으며 영구 보존 기간을 사용하여 업로드된 오브젝트는 삭제할 수 없습니다. 보존 정책이 있는 Object Storage 버킷을 사용하여 개체를 영구적으로 저장해야 하는 합법적인 필요성이 있는지 확인하는 것은 사용자의 책임입니다.
불변 오브젝트 스토리지를 사용하는 경우, 데이터에 보존 정책이 적용되는 한 IBM Cloud 계정이 IBM Cloud 정책 및 가이드라인에 따라 우수한 상태로 유지되도록 해야 합니다. 자세한 정보는 IBM Cloud 서비스 이용 약관을 참조하십시오.
다양한 규정에 대한 불변 오브젝트 스토리지 및 고려사항
불변 오브젝트 스토리지를 사용하는 경우, 클라이언트는 논의된 기능을 사용하여 일반적으로 다음을 통해 통제되는 전자 레코드 스토리지 및 보존에 대한 주요 규칙을 충족하고 준수할 수 있는지 여부를 확인해야 합니다.
- SEC(Securities and Exchange Commission)규칙 17a-4(f),
- 금융 산업 규제 기관(FINRA)규칙 4511(c)및
- 상품 선물 거래 위원회(CFTC)규칙 1.31(c)-(d)
클라이언트가 정보에 입각한 결정을 내리도록 하기 위해 IBM은 Cohasset Associates Inc.와 함께 IBM의 불변 오브젝트 스토리지에 대한 독립적인 평가를 수행했습니다. 의 불변 Object Storage 기능 평가에 대한 자세한 내용을 제공하는 코하셋 어소시에이츠의 보고서( IBM Cloud Object Storage )를 검토하세요.
액세스 및 트랜잭션의 감사
보존 매개변수, 오브젝트 보존 기간 및 법적 보존의 애플리케이션에 대한 변경사항을 검토하기 위한 불변 오브젝트 저장소의 로그 데이터 액세스는 고객 서비스 티켓을 열어 케이스별로 사용 가능합니다.
콘솔 사용
보존 정책은 새로운 빈 버킷 또는 기존 빈 버킷에 추가할 수 있으며 제거할 수 없습니다. 새 버킷의 경우 지원되는 지역에서 버킷을 작성하고 있는지 확인한 다음 보존 정책 추가 옵션을 선택하십시오. 기존 버킷의 경우 오브젝트가 없는지 확인한 다음 구성 설정으로 이동하고 버킷 보존 정책 섹션 아래에 있는 정책 작성 단추를 클릭하십시오. 어느 경우에나 최소, 최대 및 기본 보존 기간을 설정하십시오.
REST API, 라이브러리 및 SDK 사용
보존 정책으로 작동하는 애플리케이션을 지원하기 위해 IBM Cloud Object Storage SDK에 몇 가지 새로운 API가 도입되었습니다. 이 페이지의 시작 부분에서 언어( HTTP, Java, JavaScript, 또는 Python )를 선택하면 적절한 Object Storage SDK를 사용하는 예제를 볼 수 있습니다.
모든 코드 예에서는 서로 다른 메소드를 호출할 수 있는 cos라는 클라이언트 오브젝트가 있다고 가정합니다. 클라이언트 작성에 대한 세부사항은 구체적 SDK 안내서를 참조하십시오.
보존 기간 설정에 사용되는 모든 날짜 값은 그리니치 표준시입니다. 데이터 무결성을 보장하려면 Content-MD5 헤더 또는 checksum 헤더( x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-crc64nvme, x-amz-checksum-sha1 또는 x-amz-checksum-sha256 포함)가 필요합니다. SDK를 사용할 때 해시 또는 체크섬 값이 자동으로 전송된다는 점에 유의하세요.
기존 버킷에 보존 정책 추가
이 PUT 오퍼레이션 구현은 protection 조회 매개변수를 사용하여 기존 버킷의 보존 매개변수를 설정합니다. 이 오퍼레이션을 사용하면 최소, 기본 및 최대 보존 기간을 설정하거나 변경할 수 있습니다. 이 오퍼레이션을 사용하면 버킷의 보호 상태를 변경할 수도 있습니다.
보호된 버킷에 작성된 오브젝트는 보호 기간이 만료되어 오브젝트에 대한 모든 법적 보존이 제거될 때까지 삭제할 수 없습니다. 오브젝트가 작성될 때 오브젝트 고유 값이 제공되지 않으면 버킷의 기본 보존 값이 오브젝트에 지정됩니다. 보호된 버킷에서 더 이상 보존되지 않는 오브젝트(보존 기간이 만료되어 오브젝트에 대한 법적 보존이 없음)를 겹쳐쓰면 다시 보존 상태가 됩니다. 새 보존 기간은 오브젝트 겹쳐쓰기 요청의 일부로서 제공될 수 있으며, 그렇지 않은 경우에는 버킷의 기본 보존 기간이 오브젝트에 지정됩니다.
보존 기간 설정 MinimumRetention, DefaultRetention, MaximumRetention 에서 지원되는 최소 및 최대 값은 최소 0일에서 최대 36135일(99년)입니다.
Content-MD5 헤더 또는 checksum 헤더( x-amz-checksum-crc32, x-amz-checksum-crc32c,x-amz-checksum-crc64nvme, x-amz-checksum-sha1 또는 x-amz-checksum-sha256 포함)가
필요합니다. 이 오퍼레이션은 추가 조회 매개변수를 사용하지 않습니다.
엔드포인트에 대한 자세한 정보는 엔드포인트 및 스토리지 위치를 참조하십시오.
구문
PUT https://{endpoint}/{bucket-name}?protection= # path style
PUT https://{bucket-name}.{endpoint}?protection= # virtual host style
요청 예제
PUT /example-bucket?protection= HTTP/1.1
Authorization: {authorization-string}
x-amz-date: 20181011T190354Z
x-amz-content-sha256: 2938f51643d63c864fdbea618fe71b13579570a86f39da2837c922bae68d72df
Content-MD5: GQmpTNpruOyK6YrxHnpj7g==
Content-Type: text/plain
Host: 67.228.254.193
Content-Length: 299
<ProtectionConfiguration>
<Status>Retention</Status>
<MinimumRetention>
<Days>100</Days>
</MinimumRetention>
<MaximumRetention>
<Days>10000</Days>
</MaximumRetention>
<DefaultRetention>
<Days>2555</Days>
</DefaultRetention>
</ProtectionConfiguration>
응답 예
HTTP/1.1 200 OK
Date: Wed, 5 Oct 2018 15:39:38 GMT
X-Clv-Request-Id: 7afca6d8-e209-4519-8f2c-1af3f1540b42
Accept-Ranges: bytes
Server: Cleversafe/3.14.1
X-Clv-S3-Version: 2.5
x-amz-request-id: 7afca6d8-e209-4519-8f2c-1af3f1540b42
Content-Length: 0
def add_protection_configuration_to_bucket(bucket_name):
try:
new_protection_config = {
"Status": "Retention",
"MinimumRetention": {"Days": 10},
"DefaultRetention": {"Days": 100},
"MaximumRetention": {"Days": 1000}
}
cos.put_bucket_protection_configuration(Bucket=bucket_name, ProtectionConfiguration=new_protection_config)
print("Protection added to bucket {0}\n".format(bucket_name))
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to set bucket protection config: {0}".format(e))
function addProtectionConfigurationToBucket(bucketName) {
console.log(`Adding protection to bucket ${bucketName}`);
return cos.putBucketProtectionConfiguration({
Bucket: bucketName,
ProtectionConfiguration: {
'Status': 'Retention',
'MinimumRetention': {'Days': 10},
'DefaultRetention': {'Days': 100},
'MaximumRetention': {'Days': 1000}
}
}).promise()
.then(() => {
console.log(`Protection added to bucket ${bucketName}!`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void addProtectionConfigurationToBucket(String bucketName) {
System.out.printf("Adding protection to bucket: %s\n", bucketName);
BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
.withStatus(BucketProtectionStatus.Retention)
.withMinimumRetentionInDays(10)
.withDefaultRetentionInDays(100)
.withMaximumRetentionInDays(1000);
cos.setBucketProtection(bucketName, newConfig);
System.out.printf("Protection added to bucket %s\n", bucketName);
}
public static void addProtectionConfigurationToBucketWithRequest(String bucketName) {
System.out.printf("Adding protection to bucket: %s\n", bucketName);
BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
.withStatus(BucketProtectionStatus.Retention)
.withMinimumRetentionInDays(10)
.withDefaultRetentionInDays(100)
.withMaximumRetentionInDays(1000);
SetBucketProtectionConfigurationRequest newRequest = new SetBucketProtectionConfigurationRequest()
.withBucketName(bucketName)
.withProtectionConfiguration(newConfig);
cos.setBucketProtectionConfiguration(newRequest);
System.out.printf("Protection added to bucket %s\n", bucketName);
}
버킷의 보존 정책 확인
이 GET 오퍼레이션 구현은 기존 버킷에 대한 보존 매개변수를 페치합니다.
구문
GET https://{endpoint}/{bucket-name}?protection= # path style
GET https://{bucket-name}.{endpoint}?protection= # virtual host style
요청 예제
GET /example-bucket?protection= HTTP/1.1
Authorization: {authorization-string}
x-amz-date: 20181011T190354Z
Content-Type: text/plain
Host: 67.228.254.193
응답 예
HTTP/1.1 200 OK
Date: Wed, 5 Oct 2018 15:39:38 GMT
X-Clv-Request-Id: 7afca6d8-e209-4519-8f2c-1af3f1540b42
Accept-Ranges: bytes
Server: Cleversafe/3.13.1
X-Clv-S3-Version: 2.5
x-amz-request-id: 7afca6d8-e209-4519-8f2c-1af3f1540b42
Content-Length: 299
<ProtectionConfiguration>
<Status>Retention</Status>
<MinimumRetention>
<Days>100</Days>
</MinimumRetention>
<MaximumRetention>
<Days>10000</Days>
</MaximumRetention>
<DefaultRetention>
<Days>2555</Days>
</DefaultRetention>
</ProtectionConfiguration>
버킷에 보호 구성이 없는 경우 대신 서버가 사용 안함 상태로 응답합니다.
<ProtectionConfiguration>
<Status>Disabled</Status>
</ProtectionConfiguration>
def get_protection_configuration_on_bucket(bucket_name):
try:
response = cos.get_bucket_protection_configuration(Bucket=bucket_name)
protection_config = response.get("ProtectionConfiguration")
print("Bucket protection config for {0}\n".format(bucket_name))
print(protection_config)
print("\n")
except ClientError as be:
print("CLIENT ERROR: {0}\n".format(be))
except Exception as e:
print("Unable to get bucket protection config: {0}".format(e))
function getProtectionConfigurationOnBucket(bucketName) {
console.log(`Retrieve the protection on bucket ${bucketName}`);
return cos.getBucketProtectionConfiguration({
Bucket: bucketName
}).promise()
.then((data) => {
console.log(`Configuration on bucket ${bucketName}:`);
console.log(data);
}
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void getProtectionConfigurationOnBucket(String bucketName) {
System.out.printf("Retrieving protection configuration from bucket: %s\n", bucketName;
BucketProtectionConfiguration config = cos.getBucketProtection(bucketName);
String status = config.getStatus();
System.out.printf("Status: %s\n", status);
if (!status.toUpperCase().equals("DISABLED")) {
System.out.printf("Minimum Retention (Days): %s\n", config.getMinimumRetentionInDays());
System.out.printf("Default Retention (Days): %s\n", config.getDefaultRetentionInDays());
System.out.printf("Maximum Retention (Days): %s\n", config.getMaximumRetentionInDays());
}
}
보존 정책이 있는 버킷에 오브젝트 업로드
이 PUT 오퍼레이션의 개선사항에서는 세 개의 새 요청 헤더를 추가합니다. 두 개는 서로 다른 방식의 보존 기간 지정을 위한 헤더이고 하나는 새 오브젝트에 단일 법적 보존을 추가하기 위한 헤더입니다. 새 오류는 새 헤더의 잘못된 값에 대해 정의되며 오브젝트가 보존되는 경우 겹쳐쓰기에 실패합니다.
더 이상 보존되지 않는(보존 기간이 만료되었고 오브젝트에 법적 보존이 없음) 보존 정책을 사용하는 버킷의 오브젝트는 겹쳐쓸 때 다시 보존 상태가 됩니다. 새 보존 기간은 오브젝트 겹쳐쓰기 요청의 일부로서 제공될 수 있으며, 그렇지 않은 경우에는 버킷의 기본 보존 기간이 오브젝트에 지정됩니다.
Content-MD5 헤더 또는 checksum 헤더( x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-crc64nvme, x-amz-checksum-sha1 또는 x-amz-checksum-sha256 포함)는
보존 정책이 있는 버킷에 대한 모든 유형의 오브젝트 업로드 요청에 대한 페이로드의 무결성 검사로 필요합니다.
| 값 | 유형 | 설명 |
|---|---|---|
Retention-Period |
음수가 아닌 정수(초) | 오브젝트에 저장할 보존 기간(초)입니다. 오브젝트는 보존 기간에 지정된 시간이 경과하기 전까지 겹쳐쓰거나 삭제할 수 없습니다. 이 필드와 Retention-Expiration-Date가 모두 지정된 경우에는 400 오류가 리턴됩니다. 둘 다 지정되지 않은 경우에는 버킷의 DefaultRetention 기간이 사용됩니다. 영(0)은
버킷의 최소 보존 기간도 0이라고 가정하는 적법한 값입니다. |
Retention-expiration-date |
날짜(ISO 8601 형식) | 오브젝트를 적법하게 삭제하거나 수정할 수 있는 날짜입니다. 이 헤더 또는 Retention-Period 헤더만 지정할 수 있습니다. 둘 다 지정된 경우에는 400 오류가 리턴됩니다. 둘 다 지정되지 않은 경우에는 버킷의 DefaultRetention 기간이 사용됩니다. 지원되는 ISO 8601형식은 [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]Z 또는 [YYYY][MM][DD]T[hh][mm][ss]Z 입니다 (예: 2020-11-28T03:10:01Z 또는 20201128T031001Z 모두 유효함). |
Retention-legal-hold-id |
문자열 | 오브젝트에 적용할 단일 법적 보존입니다. 법적 보존은 Y자 길이의 문자열입니다. 오브젝트는 해당 오브젝트와 연관된 모든 법적 보존이 제거될 때까지 겹쳐쓰거나 삭제할 수 없습니다. |
def put_object_add_legal_hold(bucket_name, object_name, file_text, legal_hold_id):
print("Add legal hold {0} to {1} in bucket {2} with a putObject operation.\n".format(legal_hold_id, object_name, bucket_name))
cos.put_object(
Bucket=bucket_name,
Key=object_name,
Body=file_text,
RetentionLegalHoldId=legal_hold_id)
print("Legal hold {0} added to object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))
def copy_protected_object(source_bucket_name, source_object_name, destination_bucket_name, new_object_name):
print("Copy protected object {0} from bucket {1} to {2}/{3}.\n".format(source_object_name, source_bucket_name, destination_bucket_name, new_object_name))
copy_source = {
"Bucket": source_bucket_name,
"Key": source_object_name
}
cos.copy_object(
Bucket=destination_bucket_name,
Key=new_object_name,
CopySource=copy_source,
RetentionDirective="Copy"
)
print("Protected object copied from {0}/{1} to {2}/{3}\n".format(source_bucket_name, source_object_name, destination_bucket_name, new_object_name));
def complete_multipart_upload_with_retention(bucket_name, object_name, upload_id, retention_period):
print("Completing multi-part upload for object {0} in bucket {1}\n".format(object_name, bucket_name))
cos.complete_multipart_upload(
Bucket=bucket_name,
Key=object_name,
MultipartUpload={
"Parts":[{
"ETag": part["ETag"],
"PartNumber": 1
}]
},
UploadId=upload_id,
RetentionPeriod=retention_period
)
print("Multi-part upload completed for object {0} in bucket {1}\n".format(object_name, bucket_name))
def upload_file_with_retention(bucket_name, object_name, path_to_file, retention_period):
print("Uploading file {0} to object {1} in bucket {2}\n".format(path_to_file, object_name, bucket_name))
args = {
"RetentionPeriod": retention_period
}
cos.upload_file(
Filename=path_to_file,
Bucket=bucket_name,
Key=object_name,
ExtraArgs=args
)
print("File upload complete to object {0} in bucket {1}\n".format(object_name, bucket_name))
function putObjectAddLegalHold(bucketName, objectName, legalHoldId) {
console.log(`Add legal hold ${legalHoldId} to ${objectName} in bucket ${bucketName} with a putObject operation.`);
return cos.putObject({
Bucket: bucketName,
Key: objectName,
Body: 'body',
RetentionLegalHoldId: legalHoldId
}).promise()
.then((data) => {
console.log(`Legal hold ${legalHoldId} added to object ${objectName} in bucket ${bucketName}`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
function copyProtectedObject(sourceBucketName, sourceObjectName, destinationBucketName, newObjectName, ) {
console.log(`Copy protected object ${sourceObjectName} from bucket ${sourceBucketName} to ${destinationBucketName}/${newObjectName}.`);
return cos.copyObject({
Bucket: destinationBucketName,
Key: newObjectName,
CopySource: sourceBucketName + '/' + sourceObjectName,
RetentionDirective: 'Copy'
}).promise()
.then((data) => {
console.log(`Protected object copied from ${sourceBucketName}/${sourceObjectName} to ${destinationBucketName}/${newObjectName}`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void putObjectAddLegalHold(String bucketName, String objectName, String fileText, String legalHoldId) {
System.out.printf("Add legal hold %s to %s in bucket %s with a putObject operation.\n", legalHoldId, objectName, bucketName);
InputStream newStream = new ByteArrayInputStream(fileText.getBytes(StandardCharsets.UTF_8));
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(fileText.length());
PutObjectRequest req = new PutObjectRequest(
bucketName,
objectName,
newStream,
metadata
);
req.setRetentionLegalHoldId(legalHoldId);
cos.putObject(req);
System.out.printf("Legal hold %s added to object %s in bucket %s\n", legalHoldId, objectName, bucketName);
}
public static void copyProtectedObject(String sourceBucketName, String sourceObjectName, String destinationBucketName, String newObjectName) {
System.out.printf("Copy protected object %s from bucket %s to %s/%s.\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);
CopyObjectRequest req = new CopyObjectRequest(
sourceBucketName,
sourceObjectName,
destinationBucketName,
newObjectName
);
req.setRetentionDirective(RetentionDirective.COPY);
cos.copyObject(req);
System.out.printf("Protected object copied from %s/%s to %s/%s\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);
}
오브젝트에서 법적 보존 추가 또는 제거
이 POST 오퍼레이션 구현은 legalHold 조회 매개변수 및 add와 remove 조회 매개변수를 사용하여 보호된 버킷의 보호된 오브젝트에서 단일 법적 보존을 추가하거나 제거합니다.
오브젝트는 100개의 법적 보존을 지원할 수 있습니다.
- 법적 보존 ID는 최대 64자이고 최소 1자인 문자열입니다. 유효한 문자는 문자, 숫자,
!,_,.,*,(,),-,'입니다. - 특정 법적 보존을 추가했을 때 오브젝트의 총 100개 법적 보존 한계를 초과하는 경우에는 해당 새 법적 보존이 추가되지 않으며
400오류가 리턴됩니다. - ID가 너무 긴 경우에는 오브젝트에 추가되지 않으며
400오류가 리턴됩니다. - ID에 올바르지 않은 문자가 포함되어 있는 경우에는 오브젝트에 추가되지 않으며
400오류가 리턴됩니다. - ID가 이미 오브젝트에서 사용 중인 경우에는 기존 법적 보존이 수정되지 않으며 해당 ID가 이미 사용 중임을 나타내는 응답이
409오류와 함께 표시됩니다. - 오브젝트에 보존 기간 메타데이터가 없는 경우에는
400오류가 리턴되며 법적 보존 추가 또는 제거가 허용되지 않습니다.
보존 기간 헤더는 반드시 있어야 하며, 그렇지 않은 경우에는 400 오류가 리턴됩니다.
구문
POST https://{endpoint}/{bucket-name}/{object-name}?legalHold # path style
POST https://{bucket-name}.{endpoint}/{object-name}?legalHold= # virtual host style
요청 예제
POST /BucketName/ObjectName?legalHold&add=legalHoldID HTTP/1.1
Host: myBucket.mydsNet.corp.com
Date: Fri, 8 Dec 2018 17:50:00 GMT
Authorization: authorization string
Content-Type: text/plain
응답 예
HTTP/1.1 200 OK
Date: Fri, 8 Dec 2018 17:51:00 GMT
Connection: close
def add_legal_hold_to_object(bucket_name, object_name, legal_hold_id):
print("Adding legal hold {0} to object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))
cos.add_legal_hold(
Bucket=bucket_name,
Key=object_name,
RetentionLegalHoldId=legal_hold_id
)
print("Legal hold {0} added to object {1} in bucket {2}!\n".format(legal_hold_id, object_name, bucket_name))
def delete_legal_hold_from_object(bucket_name, object_name, legal_hold_id):
print("Deleting legal hold {0} from object {1} in bucket {2}\n".format(legal_hold_id, object_name, bucket_name))
cos.delete_legal_hold(
Bucket=bucket_name,
Key=object_name,
RetentionLegalHoldId=legal_hold_id
)
print("Legal hold {0} deleted from object {1} in bucket {2}!\n".format(legal_hold_id, object_name, bucket_name))
function addLegalHoldToObject(bucketName, objectName, legalHoldId) {
console.log(`Adding legal hold ${legalHoldId} to object ${objectName} in bucket ${bucketName}`);
return cos.client.addLegalHold({
Bucket: bucketName,
Key: objectId,
RetentionLegalHoldId: legalHoldId
}).promise()
.then(() => {
console.log(`Legal hold ${legalHoldId} added to object ${objectName} in bucket ${bucketName}!`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
function deleteLegalHoldFromObject(bucketName, objectName, legalHoldId) {
console.log(`Deleting legal hold ${legalHoldId} from object ${objectName} in bucket ${bucketName}`);
return cos.client.deleteLegalHold({
Bucket: bucketName,
Key: objectId,
RetentionLegalHoldId: legalHoldId
}).promise()
.then(() => {
console.log(`Legal hold ${legalHoldId} deleted from object ${objectName} in bucket ${bucketName}!`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void addLegalHoldToObject(String bucketName, String objectName, String legalHoldId) {
System.out.printf("Adding legal hold %s to object %s in bucket %s\n", legalHoldId, objectName, bucketName);
cos.addLegalHold(
bucketName,
objectName,
legalHoldId
);
System.out.printf("Legal hold %s added to object %s in bucket %s!\n", legalHoldId, objectName, bucketName);
}
public static void deleteLegalHoldFromObject(String bucketName, String objectName, String legalHoldId) {
System.out.printf("Deleting legal hold %s from object %s in bucket %s\n", legalHoldId, objectName, bucketName);
cos.deleteLegalHold(
bucketName,
objectName,
legalHoldId
);
System.out.printf("Legal hold %s deleted from object %s in bucket %s!\n", legalHoldId, objectName, bucketName);
}
오브젝트의 보존 기간 연장
이 POST 오퍼레이션 구현은 extendRetention 조회 매개변수를 사용하여 보호된 버킷에서 보호된 오브젝트의 보존 기간을 연장합니다.
오브젝트의 보존 기간은 연장만 가능합니다. 현재 구성된 값에서 줄일 수는 없습니다.
보존 연장 값은 다음 세 가지 방법 중 하나로 설정됩니다.
- 현재 값에서의 추가 시간(
Additional-Retention-Period또는 이와 유사한 메소드) - 초 단위의 새 연장 기간(
Extend-Retention-From-Current-Time또는 이와 유사한 메소드) - 오브젝트의 새 보존 만료 날짜(
New-Retention-Expiration-Date또는 이와 유사한 메소드)
오브젝트 메타데이터에 저장된 현재 보존 기간은 extendRetention 요청에 설정된 매개변수에 따라 지정된 추가 시간만큼 증가되거나, 새 값으로 대체될 수 있습니다. 모든 경우에 보존 연장 매개변수는 현재 보존 기간에 대해 확인되며, 연장된 매개변수는 업데이트된 보존 기간이 현재 보존 기간보다 긴 경우에만 허용됩니다.
New-Retention-Expiration-Date 에 대해 지원되는 ISO 8601형식은 [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]Z 또는 [YYYY][MM][DD]T[hh][mm][ss]Z 입니다 (예를 들어, 2020-11-28T03:10:01Z 또는 20201128T031001Z 모두 유효함).
보호된 버킷에서 더 이상 보존되지 않는 오브젝트(보존 기간이 만료되어 오브젝트에 대한 법적 보존이 없음)를 겹쳐쓰면 다시 보존 상태가 됩니다. 새 보존 기간은 오브젝트 겹쳐쓰기 요청의 일부로서 제공될 수 있으며, 그렇지 않은 경우에는 버킷의 기본 보존 기간이 오브젝트에 지정됩니다.
구문
POST https://{endpoint}/{bucket-name}/{object-name}?extendRetention= # path style
POST https://{bucket-name}.{endpoint}/{object-name}?extendRetention= # virtual host style
요청 예제
POST /BucketName/ObjectName?extendRetention HTTP/1.1
Host: myBucket.mydsNet.corp.com
Date: Fri, 8 Dec 2018 17:50:00GMT
Authorization: authorization string
Content-Type: text/plain
Additional-Retention-Period: 31470552
응답 예
HTTP/1.1 200 OK
Date: Fri, 8 Dec 2018 17:50:00GMT
Connection: close
def extend_retention_period_on_object(bucket_name, object_name, additional_seconds):
print("Extend the retention period on {0} in bucket {1} by {2} seconds.\n".format(object_name, bucket_name, additional_seconds))
cos.extend_object_retention(
Bucket=bucket_ame,
Key=object_name,
AdditionalRetentionPeriod=additional_seconds
)
print("New retention period on {0} is {1}\n".format(object_name, additional_seconds))
function extendRetentionPeriodOnObject(bucketName, objectName, additionalSeconds) {
console.log(`Extend the retention period on ${objectName} in bucket ${bucketName} by ${additionalSeconds} seconds.`);
return cos.extendObjectRetention({
Bucket: bucketName,
Key: objectName,
AdditionalRetentionPeriod: additionalSeconds
}).promise()
.then((data) => {
console.log(`New retention period on ${objectName} is ${data.RetentionPeriod}`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void extendRetentionPeriodOnObject(String bucketName, String objectName, Long additionalSeconds) {
System.out.printf("Extend the retention period on %s in bucket %s by %s seconds.\n", objectName, bucketName, additionalSeconds);
ExtendObjectRetentionRequest req = new ExtendObjectRetentionRequest(
bucketName,
objectName)
.withAdditionalRetentionPeriod(additionalSeconds);
cos.extendObjectRetention(req);
System.out.printf("New retention period on %s is %s\n", objectName, additionalSeconds);
}
오브젝트의 법적 보존 나열
이 GET 오퍼레이션 구현은 legalHold 조회 매개변수를 사용하여 XML 응답 본문에 오브젝트의 법적 보존 목록 및 관련 보존 상태를 리턴합니다.
이 오퍼레이션은 다음 항목을 리턴합니다.
- 오브젝트 작성 날짜
- 오브젝트 보존 기간(초)
- 보존 기간 및 작성 날짜를 기반으로 계산된 보존 만료 날짜
- 법적 보존의 목록
- 법적 보존 ID
- 법적 보존이 적용된 시점의 시간소인
오브젝트에 대한 법적 보존이 없는 경우에는 비어 있는 LegalHoldSet이 리턴됩니다. 오브젝트에 대해 지정된 보존 기간이 없는 경우에는 404 오류가 리턴됩니다.
구문
GET https://{endpoint}/{bucket-name}/{object-name}?legalHold= # path style
GET https://{bucket-name}.{endpoint}/{object-name}?legalHold= # virtual host style
요청 예제
GET /BucketName/ObjectName?legalHold HTTP/1.1
Host: myBucket.mydsNet.corp.com
Date: Fri, 8 Dec 2018 17:50:00 GMT
Authorization: {authorization-string}
Content-Type: text/plain
응답 예
HTTP/1.1 200 OK
Date: Fri, 8 Dec 2018 17:51:00 GMT
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
<RetentionState>
<CreateTime>Fri, 8 Sep 2018 21:33:08 GMT</CreateTime>
<RetentionPeriod>220752000</RetentionPeriod>
<RetentionPeriodExpirationDate>Fri, 1 Sep 2023 21:33:08
GMT</RetentionPeriodExpirationDate>
<LegalHoldSet>
<LegalHold>
<ID>SomeLegalHoldID</ID>
<Date>Fri, 8 Sep 2018 23:13:18 GMT</Date>
</LegalHold>
<LegalHold>
...
</LegalHold>
</LegalHoldSet>
</RetentionState>
def list_legal_holds_on_object(bucket_name, object_name):
print("List all legal holds on object {0} in bucket {1}\n".format(object_name, bucket_name));
response = cos.list_legal_holds(
Bucket=bucket_name,
Key=object_name
)
print("Legal holds on bucket {0}: {1}\n".format(bucket_name, response))
function listLegalHoldsOnObject(bucketName, objectName) {
console.log(`List all legal holds on object ${objectName} in bucket ${bucketName}`);
return cos.listLegalHolds({
Bucket: bucketName,
Key: objectId
}).promise()
.then((data) => {
console.log(`Legal holds on bucket ${bucketName}: ${data}`);
})
.catch((e) => {
console.log(`ERROR: ${e.code} - ${e.message}\n`);
});
}
public static void listLegalHoldsOnObject(String bucketName, String objectName) {
System.out.printf("List all legal holds on object %s in bucket %s\n", objectName, bucketName);
ListLegalHoldsResult result = cos.listLegalHolds(
bucketName,
objectName
);
System.out.printf("Legal holds on bucket %s: \n", bucketName);
List<LegalHold> holds = result.getLegalHolds();
for (LegalHold hold : holds) {
System.out.printf("Legal Hold: %s", hold);
}
}