使用 Immutable Object Storage 來保護儲存區
Immutable Object Storage 會保留電子記錄,並維護資料完整性。 保留原則確保資料以 WORM(一寫多讀)、不可消除且不可重寫的方式進行儲存。 除非保留期間結束以及移除所有合法保留,否則會施行此原則。
Object Storage for Satellite 目前不支援此功能。 進一步瞭解。
在保留期間結束之前會施行原則,且在保留期間過期之前無法變更原則。 雖然 IBM Cloud Object Storage 使用 S3 API 進行大部分操作,但用於設定保留政策的 API 與 S3 API 並不相同,儘管有些術語可能是共用的。 請仔細閱讀本文件,以防止您組織中的任何使用者建立無法刪除的物件,即使是 IBM Cloud 管理員也無法刪除。
任何需要在其環境中長期保留資料的使用者都可以使用此特性,包括但不限於下列產業中的組織:
- 金融
- 醫療保健
- 媒體內容存檔
- 尋求防止特許修改或刪除物件或文件的任何人
保留原則也可以供處理金融記錄管理的組織(例如經紀商/自營商交易)使用,而且可能需要以不可重寫及不可消除的格式來儲存資料。
只有特定地區才提供 Immutable Object Storage。如需詳細資料,請參閱整合式服務。 它同時需要標準定價方案。 如需詳細資料,請參閱定價。
不可以搭配使用 Aspera 高速傳送與具有保留原則的儲存區。
術語與用法
保留期間
物件必須儲存在 IBM Cloud Object Storage 桶中的時間長度。
保留原則 (Retention policy)
保留政策在 IBM Cloud Object Storage 桶層級啟用。 此原則定義保留期間下限、上限及預設保留期間,並將其套用至儲存區中的所有物件。
保留期間下限是物件必須保留在儲存區中的持續時間下限。
保留期間上限是物件可以保留在儲存區中的持續時間上限。
如果物件儲存在儲存區中,但未指定自訂保留期間,則會使用預設保留期間。 保留期間下限必須小於或等於預設保留期間,而預設保留期間必須小於或等於保留期間上限。
可為物件指定最長 99 年的保留期限。
若要在儲存區上建立保留原則,您需要「管理員」角色。 如需詳細資料,請參閱儲存區許可權。
合法保留 (Legal hold)
在保留期間到期後,可能需要防止修改某些物件。 例如,對於未完成的法律審查,在初始設定的保留期間之後,可能需要延長保留期間,以繼續存取其中的記錄。 然後可以在物件層次套用合法保留旗標。 在初始上傳物件期間或寫入物件之後,可以將合法保留套用至物件。 附註:每個物件最多可以套用 100 個合法保留。
無限期保留 (Indefinite retention)
容許使用者將物件設定為無限期儲存,直到套用新的保留期間為止。 這是根據物件層次所設定的。
使用不定期保留的物件並非完全不可變,直到該物件的保留從 -1 轉換成某個正數的有限值。 雖然使用 -1 (無限保留) 寫入的物件無法使用 DELETE object 或覆寫請求刪除,但物件的保留期限仍可從 -1 更新為目前的日期/時間,這將使物件可立即刪除。
使用者在評估其儲存需求的可行性時應考慮此行為。 無限期保留的常見用例描述於 基於事件的保留。 在或想要使用基於事件的保留時,ImmutableObject Storage如果使用者在物件首次上傳到系統時不確定保留需求,則允許使用者對物件設定無限期保留。 一旦設定為無限期,用戶應用程式就可以在發生特定事件時將物件保留更改為有限值。
範例 鑑於某公司有保留員工記錄至員工離職後三年的政策。
- 當員工加入並開始為公司工作時,與該員工關聯的記錄可以無限期地保留。
- 而當同一位員工離開公司時,無限期的保留就會轉換成公司政策所定義的自目前起三年內的有限值。
使用者或協力廠商應用程式可以使用 SDK 或 REST API,將保留期間從無限期變更為有限保留。
儲存桶擁有者和允許的使用者可以限制可為目前使用無限期保留保留的物件配置的新保留。 這是透過利用儲存桶保留最小和最大允許值來完成的。 透過這樣做,使用者可以防止無限期保留的物件將其保留更新到當前時間以便立即刪除的情況。
事件型保留 (Event-based retention)
Immutable Object Storage 容許使用者在不確定保留期間的最終持續時間時,或想要使用事件型保留時,設定無限期保留物件。 設為無限期之後,使用者應用程式可以在之後將物件保留變更為有限值。 例如,公司具有在員工離開公司之後保留員工記錄三年的原則。 員工加入公司時,就可以無限期保留與該員工相關聯的記錄。 員工離開公司時,即會將無限期保留轉換為從現行時間算起 3 年的有限值(由公司原則所定義)。 接著,在保留期間變更之後,該物件會受到保護 3 年。 使用者或協力廠商應用程式可以使用 SDK 或 REST API,將保留期間從無限期變更為有限保留。
永久保留 (Permanent retention)
永久保留可確保任何人都無法刪除資料。 請仔細閱讀文件,並不要使用永久保留,除非 永久 資料儲存有令人信服的法規或法規遵循需求。
永久保留只能在 IBM Cloud Object Storage 儲存桶層級啟用保留政策,使用者能在上傳物件時選擇永久保留期間選項。 啟用之後,就無法回復此處理程序,而且無法刪除使用永久保留期間所上傳的物件。 使用者有責任使用 Object Storage 儲存桶與保留政策來驗證是否有永久儲存物件的合法需求。
使用 Immutable Object Storage 時,您負責確保只要資料受到保留原則的約束,「IBM Cloud 帳戶」就能根據 IBM Cloud 原則及準則保持良好狀態。 如需相關資訊,請參閱「IBM Cloud 服務」條款。
Immutable Object Storage 及各種法規的考量
使用 Immutable Object Storage 時,用戶端必須負責檢查並確定是否可以使用所討論的所有特性功能,來滿足並遵守一般由下列項目所控管的電子記錄儲存和保留的關鍵規則:
為了協助用戶端做出明智的決策,IBM 已與 Cohasset Associates Inc. 合作,對 IBM 的 Immutable Object Storage 進行獨立評量。 檢閱 Cohasset Associates Inc. 的報告,提供有關 IBM Cloud Object Storage 的 Immutable Object Storage 功能評估的詳細資訊。
存取及交易的審核
藉由開立客戶服務問題單,即可逐案提供 Immutable 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錯誤。 - 如果物件沒有保留期間 meta 資料,則會傳回
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或類似方法)
物件 meta 資料中所儲存的現行保留期間可透過給定的額外時間增加,或取代為新值,視 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);
}
}