kubernetes/kops · error
failed to get grant for key %q in bucket %q: %w
Error message
failed to get grant for key %q in bucket %q: %w
What it means
S3Path.IsPublic inspects the object ACL via GetObjectAcl to see whether the AllUsers group has READ permission. This error wraps any failure of that call — most commonly the caller lacks s3:GetObjectAcl, or the key/bucket doesn't exist. The AWS error is embedded via %w.
Source
Thrown at util/pkg/vfs/s3fs.go:667
// return allowsAnonymousRead, nil
}
func (p *S3Path) IsPublic() (bool, error) {
if p.scheme == "linode" {
// Akamai (Linode) does not implement GetObjectAcl. In that case we conservatively treat the object as non-public and continue.
return false, nil
}
ctx := context.TODO()
client, err := p.client(ctx)
if err != nil {
return false, err
}
acl, err := client.GetObjectAcl(ctx, &s3.GetObjectAclInput{
Bucket: &p.bucket,
Key: &p.key,
})
if err != nil {
return false, fmt.Errorf("failed to get grant for key %q in bucket %q: %w", p.key, p.bucket, err)
}
for _, grant := range acl.Grants {
if aws.ToString(grant.Grantee.URI) == "http://acs.amazonaws.com/groups/global/AllUsers" {
return grant.Permission == types.PermissionRead, nil
}
}
return false, nil
}
type terraformS3File struct {
Bucket string `json:"bucket" cty:"bucket"`
Key string `json:"key" cty:"key"`
Content *terraformWriter.Literal `json:"content,omitempty" cty:"content"`
Acl *string `json:"acl,omitempty" cty:"acl"`
SSE *string `json:"server_side_encryption,omitempty" cty:"server_side_encryption"`
Provider *terraformWriter.Literal `json:"provider,omitempty" cty:"provider"`
}View on GitHub (pinned to 4c8573c808)
Solutions
- Grant s3:GetObjectAcl on the bucket/objects to the calling principal if the wrapped error is AccessDenied.
- If ACLs are disabled (Object Ownership: Bucket owner enforced), use GetBucketPolicyStatus or GetObjectAttributes instead of ACL-based checks.
- Verify the key exists (head the object) before the ACL check to rule out NoSuchKey.
- Confirm bucket name and region if the wrapped error is NoSuchBucket.
Example fix
// before (policy)
{"Action":["s3:GetObject"]}
// after
{"Action":["s3:GetObject","s3:GetObjectAcl"]} Defensive patterns
Strategy: type-guard
Validate before calling
// check key existence and ACL permission first
_, err := client.HeadObject(ctx, &s3.HeadObjectInput{Bucket: aws.String(bucket), Key: aws.String(key)})
if err != nil { // NoSuchKey/AccessDenied — resolve before GetObjectAcl }
// verify ACLs aren't disabled (Object Ownership: Bucket owner enforced)
ownership, _ := client.GetBucketOwnershipControls(ctx, &s3.GetBucketOwnershipControlsInput{Bucket: aws.String(bucket)}) Type guard
func aclAPIDisabled(ownership *s3.GetBucketOwnershipControlsOutput) bool {
return ownership != nil && ownership.OwnershipControls != nil &&
ownership.OwnershipControls.Rules[0].ObjectOwnership == types.ObjectOwnershipBucketOwnerEnforced
} Try / catch
isPublic, err := s3Path.IsPublic()
if err != nil {
if vfs.AWSErrorCode(err) == "AccessDenied" || strings.Contains(err.Error(), "ObjectOwnershipControls") {
// ACLs disabled — audit via bucket policy instead of object ACL
return s3Path.IsBucketPublic()
}
return false, err
} Prevention
- Grant s3:GetObjectAcl alongside s3:GetObject for any identity that audits object visibility.
- Prefer policy-based checks (GetBucketPolicyStatus) when the bucket has ACLs disabled.
- Head the object first to avoid confusing NoSuchKey with ACL failures.
- Standardize on Bucket-owner-enforced ownership and policy-based public checks org-wide.
When it happens
Trigger: Calling IsPublic on an S3Path when GetObjectAcl fails: AccessDenied on the object, NoSuchKey (object deleted), or NoSuchBucket — anything except a successful ACL response.
Common situations: Security scans checking state-file ACLs with an IAM role that has GetObject but not GetObjectAcl; buckets with Object Ownership set to 'Bucket owner enforced' (ACLs disabled) causing API failures; audited keys that were since deleted.
Related errors
- error writing %s (with ACL=%q): %v
- from AWS S3 GetBucketPolicyStatusWithContext: %w
- failed to generate AWS IAM S3 access statements: %v
- unknown writeable path, can't apply IAM policy: %q
- checking if bucket was public: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/0d127e9c5d1f7c98.
Report an issue: GitHub.