Repository navigation
Storage Bucket Policy
Bucket policy calls for danny.vn/vngcloud/storage: GetBucketPolicy,
PutBucketPolicy, and DeleteBucketPolicy. A bucket policy gives a service
account's key rights on one bucket. See Storage for buckets, S3
keys, and attaching a key to a service account.
This page assumes cfg, ctx, and client := storage.New(cfg) from
Storage's Setup.
All three calls take ProjectID and Bucket, and Region works as in
Storage. PutBucketPolicy also takes Policy, the
document as JSON text.
principal, err := client.EnsureServiceAccountPrincipal(ctx,
&storage.EnsureServiceAccountPrincipalInput{
ProjectID: projectID,
ServiceAccountID: serviceAccountID,
})
if err != nil {
log.Fatal(err)
}
policy := buildPolicy(principal.PrincipalARN, bucket) // the template below
_, err = client.PutBucketPolicy(ctx, &storage.PutBucketPolicyInput{
ProjectID: projectID,
Bucket: bucket,
Policy: policy,
})
got, err := client.GetBucketPolicy(ctx, &storage.GetBucketPolicyInput{
ProjectID: projectID,
Bucket: bucket,
})
if err != nil {
log.Fatal(err)
}
log.Println(got.Policy == "") // true when the bucket has no policy
_, err = client.DeleteBucketPolicy(ctx, &storage.DeleteBucketPolicyInput{
ProjectID: projectID,
Bucket: bucket,
})-
GetBucketPolicyreturnsPolicyas the server sends it. A bucket with no policy givesPolicy ""and no error. The server may change whitespace and key order, so compare decoded documents, not strings. -
PutBucketPolicyreplaces the whole policy. It sendsPolicyunchanged as a JSON string. APolicythat is not a JSON object with a non-emptyStatementarray returnsvngcloud.ErrInvalidInput, and nothing is sent. So does a statement that is not a JSON object or lacks a non-emptyEffect,Principal,Action, orResource. The error names the statement index and the field. To remove every statement, callDeleteBucketPolicy. -
DeleteBucketPolicysucceeds when the bucket has no policy, so a repeat delete returns the same result. - Put and delete give the same result when repeated, so both keep the transport's retries.
- A put, a delete, and an attach reach the data plane within about a second.
This policy gives one principal object work in one bucket and nothing on the
bucket's settings. Fill in the principal from PrincipalARN and the bucket
name:
{"Version": "2012-10-17", "Statement": [
{"Sid": "Bucket", "Effect": "Allow",
"Principal": {"AWS": ["<PrincipalARN>"]},
"Action": ["s3:ListBucket", "s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"],
"Resource": ["arn:aws:s3:::<bucket>"]},
{"Sid": "Objects", "Effect": "Allow",
"Principal": {"AWS": ["<PrincipalARN>"]},
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject",
"s3:AbortMultipartUpload", "s3:ListMultipartUploadParts"],
"Resource": ["arn:aws:s3:::<bucket>/*"]}]}The template names object actions and does not use s3:*. In S3, s3:* also
grants the bucket delete and policy changes on that bucket, so a leaked key
could delete the bucket or rewrite its policy. Whether this server lets a
non-owner do so is not checked, and the template avoids the question.
A bucket policy is the one way to serve objects anonymously: the console's public access route answers 403 to an IAM user, and the ACL route opens the bucket listing but no object. This policy grants anonymous object reads and no listing:
{"Version": "2012-10-17", "Statement": [
{"Sid": "PublicRead", "Effect": "Allow", "Principal": "*",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::<bucket>/*"]}]}A bucket policy holds one document, so a bucket that also has a per-bucket key
keeps the key's statements in the same document. Deleting the policy ends
public reads at once. GetBucket reports no public state: IsPublic stays
false whatever the policy says.
put-bucket-policy needs --yes when the document has a public principal, and
exits 2 with no request otherwise. A statement has one when its Effect is not
Deny and its Principal is a string containing *, or an object whose AWS
value is such a string or an array holding one. PolicyHasPublicPrincipal
returns that answer for SDK callers, or the error PutBucketPolicy would
return for the document:
public, err := storage.PolicyHasPublicPrincipal(policy)- An attached key lists every bucket of the project and can create a bucket, but cannot put or delete objects in it, or delete it.
- A
GETof a missing object answers 404NoSuchKeyeven in a bucket the key cannot read, so a key learns which object names exist anywhere in the project. Do not put secrets in object names. - An attach makes the service account's sub-user. Call
EnsureServiceAccountPrincipalonly to getPrincipalARNfor a policy. - The server does not check principals. A policy that names no real sub-user,
such as a mistyped ARN or a deleted service account, is accepted and grants
nothing. Copy
PrincipalARNfromEnsureServiceAccountPrincipal, and check access with the attached key. -
PutBucketPolicyrefuses a statement with noPrincipal, including{}, because the server accepts one and then answers the console API'sGetBucketPolicy,DeleteBucketPolicy, andDeleteBucketfor that bucket with an empty body (EmptyResponse). A policy put by another tool can still cause this. The S3DeleteBucketPolicycall, made with an S3 key that is not attached, removes the policy and restores the console calls. - A
Principalof"*"grants anonymous reads the moment the put succeeds. The CLI asks for--yesfirst;PutBucketPolicydoes not, so SDK callers can check withPolicyHasPublicPrincipal. -
PutBucketPolicyalso refuses a document that repeats a member name at the top level, in a statement, or in aPrincipal, because the server reads every occurrence and this SDK would read only the last. Names are compared without regard to case. - Policy member names must be spelled exactly:
Version,Statement,Sid,Effect,Principal,NotPrincipal,Action,NotAction,Resource,NotResource,Condition,AWS,Service,Federated, andCanonicalUser.PutBucketPolicyandPolicyHasPublicPrincipalreturnvngcloud.ErrInvalidInputfor a member that matches one of them in another case, such asawsorprincipal, and name the member. The server also refuses non-canonical names with code 400 (checked foraws,effect,principal,statement, and a lower caseallowvalue), so the check is a second guard. - A policy whose only statement allows
s3:GetObjectto{"AWS": "*"}makes the console'sDeleteBucketPolicyandDeleteBucketanswer code 403, while"Principal": "*"does not. The S3DeleteBucketPolicycall, made with an S3 key that is not attached, removes it. Prefer"Principal": "*"for public reads. - Remove a service account from its bucket policies before you delete it: a new service account with the same name gets the same principal.
| Case | Result |
|---|---|
| Missing field, bad project ID or bucket name, unmapped region |
vngcloud.ErrInvalidInput, no call sent |
Policy is not a JSON object with a non-empty Statement array, a statement lacks a non-empty Effect, Principal, Action, or Resource, a member name is repeated, or a known member name is not spelled exactly |
vngcloud.ErrInvalidInput, no call sent |
The server cannot parse the policy: envelope code 400, such as an unknown Version or Effect
|
*vngcloud.APIError with the parser's message, no sentinel |
Envelope code 114
|
*vngcloud.APIError with the server's message, no sentinel |
| A policy call on a bucket that does not exist |
vngcloud.ErrNotFound: the server answers HTTP 200 with no body, so the SDK reads the bucket once. If the bucket exists, the call returns *vngcloud.APIError, code EmptyResponse
|
GetBucketPolicy data that is not a string |
*vngcloud.APIError, code InvalidResponse
|
| HTTP 403 | vngcloud.ErrPermission |
See Errors for APIError itself.
SDK
- Getting Started
- Authentication
- Configuration
- Errors
- Services
- Backup
- Billing and Pricing
- CDN
- Compute
- Compute Servers
- DNS
- Container Registry
- IAM
- Load Balancer
- Monitor
- Monitor Alerts
- Monitor Log Alarms
- Network
- Network Route Tables
- Network ACLs
- Network DHCP Options
- Network Virtual IPs
- Tagging
- Storage
- Storage Workload Access
- Storage Objects
- Storage Object Copy
- Storage: Projects
- Storage: Bucket Policy
- Storage: Bucket Settings
- Security
- Volume
- VKS
- Limitations
CLI