| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618 |
- package s3api
- import (
- "time"
- "github.com/seaweedfs/seaweedfs/weed/iam/policy"
- )
- // S3PolicyTemplates provides pre-built IAM policy templates for common S3 use cases
- type S3PolicyTemplates struct{}
- // NewS3PolicyTemplates creates a new policy templates provider
- func NewS3PolicyTemplates() *S3PolicyTemplates {
- return &S3PolicyTemplates{}
- }
- // GetS3ReadOnlyPolicy returns a policy that allows read-only access to all S3 resources
- func (t *S3PolicyTemplates) GetS3ReadOnlyPolicy() *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "S3ReadOnlyAccess",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:GetObjectVersion",
- "s3:ListBucket",
- "s3:ListBucketVersions",
- "s3:GetBucketLocation",
- "s3:GetBucketVersioning",
- "s3:ListAllMyBuckets",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- },
- },
- }
- }
- // GetS3WriteOnlyPolicy returns a policy that allows write-only access to all S3 resources
- func (t *S3PolicyTemplates) GetS3WriteOnlyPolicy() *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "S3WriteOnlyAccess",
- Effect: "Allow",
- Action: []string{
- "s3:PutObject",
- "s3:PutObjectAcl",
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- "s3:AbortMultipartUpload",
- "s3:ListMultipartUploads",
- "s3:ListParts",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- },
- },
- }
- }
- // GetS3AdminPolicy returns a policy that allows full admin access to all S3 resources
- func (t *S3PolicyTemplates) GetS3AdminPolicy() *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "S3FullAccess",
- Effect: "Allow",
- Action: []string{
- "s3:*",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- },
- },
- }
- }
- // GetBucketSpecificReadPolicy returns a policy for read-only access to a specific bucket
- func (t *S3PolicyTemplates) GetBucketSpecificReadPolicy(bucketName string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "BucketSpecificReadAccess",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:GetObjectVersion",
- "s3:ListBucket",
- "s3:ListBucketVersions",
- "s3:GetBucketLocation",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- },
- },
- }
- }
- // GetBucketSpecificWritePolicy returns a policy for write-only access to a specific bucket
- func (t *S3PolicyTemplates) GetBucketSpecificWritePolicy(bucketName string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "BucketSpecificWriteAccess",
- Effect: "Allow",
- Action: []string{
- "s3:PutObject",
- "s3:PutObjectAcl",
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- "s3:AbortMultipartUpload",
- "s3:ListMultipartUploads",
- "s3:ListParts",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- },
- },
- }
- }
- // GetPathBasedAccessPolicy returns a policy that restricts access to a specific path within a bucket
- func (t *S3PolicyTemplates) GetPathBasedAccessPolicy(bucketName, pathPrefix string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "ListBucketPermission",
- Effect: "Allow",
- Action: []string{
- "s3:ListBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- },
- Condition: map[string]map[string]interface{}{
- "StringLike": map[string]interface{}{
- "s3:prefix": []string{pathPrefix + "/*"},
- },
- },
- },
- {
- Sid: "PathBasedObjectAccess",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:PutObject",
- "s3:DeleteObject",
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- "s3:AbortMultipartUpload",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName + "/" + pathPrefix + "/*",
- },
- },
- },
- }
- }
- // GetIPRestrictedPolicy returns a policy that restricts access based on source IP
- func (t *S3PolicyTemplates) GetIPRestrictedPolicy(allowedCIDRs []string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "IPRestrictedS3Access",
- Effect: "Allow",
- Action: []string{
- "s3:*",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- Condition: map[string]map[string]interface{}{
- "IpAddress": map[string]interface{}{
- "aws:SourceIp": allowedCIDRs,
- },
- },
- },
- },
- }
- }
- // GetTimeBasedAccessPolicy returns a policy that allows access only during specific hours
- func (t *S3PolicyTemplates) GetTimeBasedAccessPolicy(startHour, endHour int) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "TimeBasedS3Access",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:PutObject",
- "s3:ListBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- Condition: map[string]map[string]interface{}{
- "DateGreaterThan": map[string]interface{}{
- "aws:CurrentTime": time.Now().Format("2006-01-02") + "T" +
- formatHour(startHour) + ":00:00Z",
- },
- "DateLessThan": map[string]interface{}{
- "aws:CurrentTime": time.Now().Format("2006-01-02") + "T" +
- formatHour(endHour) + ":00:00Z",
- },
- },
- },
- },
- }
- }
- // GetMultipartUploadPolicy returns a policy specifically for multipart upload operations
- func (t *S3PolicyTemplates) GetMultipartUploadPolicy(bucketName string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "MultipartUploadOperations",
- Effect: "Allow",
- Action: []string{
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- "s3:AbortMultipartUpload",
- "s3:ListMultipartUploads",
- "s3:ListParts",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- },
- {
- Sid: "ListBucketForMultipart",
- Effect: "Allow",
- Action: []string{
- "s3:ListBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- },
- },
- },
- }
- }
- // GetPresignedURLPolicy returns a policy for generating and using presigned URLs
- func (t *S3PolicyTemplates) GetPresignedURLPolicy(bucketName string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "PresignedURLAccess",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:PutObject",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- Condition: map[string]map[string]interface{}{
- "StringEquals": map[string]interface{}{
- "s3:x-amz-signature-version": "AWS4-HMAC-SHA256",
- },
- },
- },
- },
- }
- }
- // GetTemporaryAccessPolicy returns a policy for temporary access with expiration
- func (t *S3PolicyTemplates) GetTemporaryAccessPolicy(bucketName string, expirationHours int) *policy.PolicyDocument {
- expirationTime := time.Now().Add(time.Duration(expirationHours) * time.Hour)
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "TemporaryS3Access",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:PutObject",
- "s3:ListBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- Condition: map[string]map[string]interface{}{
- "DateLessThan": map[string]interface{}{
- "aws:CurrentTime": expirationTime.UTC().Format("2006-01-02T15:04:05Z"),
- },
- },
- },
- },
- }
- }
- // GetContentTypeRestrictedPolicy returns a policy that restricts uploads to specific content types
- func (t *S3PolicyTemplates) GetContentTypeRestrictedPolicy(bucketName string, allowedContentTypes []string) *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "ContentTypeRestrictedUpload",
- Effect: "Allow",
- Action: []string{
- "s3:PutObject",
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- Condition: map[string]map[string]interface{}{
- "StringEquals": map[string]interface{}{
- "s3:content-type": allowedContentTypes,
- },
- },
- },
- {
- Sid: "ReadAccess",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:ListBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::" + bucketName,
- "arn:seaweed:s3:::" + bucketName + "/*",
- },
- },
- },
- }
- }
- // GetDenyDeletePolicy returns a policy that allows all operations except delete
- func (t *S3PolicyTemplates) GetDenyDeletePolicy() *policy.PolicyDocument {
- return &policy.PolicyDocument{
- Version: "2012-10-17",
- Statement: []policy.Statement{
- {
- Sid: "AllowAllExceptDelete",
- Effect: "Allow",
- Action: []string{
- "s3:GetObject",
- "s3:GetObjectVersion",
- "s3:PutObject",
- "s3:PutObjectAcl",
- "s3:ListBucket",
- "s3:ListBucketVersions",
- "s3:CreateMultipartUpload",
- "s3:UploadPart",
- "s3:CompleteMultipartUpload",
- "s3:AbortMultipartUpload",
- "s3:ListMultipartUploads",
- "s3:ListParts",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- },
- {
- Sid: "DenyDeleteOperations",
- Effect: "Deny",
- Action: []string{
- "s3:DeleteObject",
- "s3:DeleteObjectVersion",
- "s3:DeleteBucket",
- },
- Resource: []string{
- "arn:seaweed:s3:::*",
- "arn:seaweed:s3:::*/*",
- },
- },
- },
- }
- }
- // Helper function to format hour with leading zero
- func formatHour(hour int) string {
- if hour < 10 {
- return "0" + string(rune('0'+hour))
- }
- return string(rune('0'+hour/10)) + string(rune('0'+hour%10))
- }
- // PolicyTemplateDefinition represents metadata about a policy template
- type PolicyTemplateDefinition struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Category string `json:"category"`
- UseCase string `json:"use_case"`
- Parameters []PolicyTemplateParam `json:"parameters,omitempty"`
- Policy *policy.PolicyDocument `json:"policy"`
- }
- // PolicyTemplateParam represents a parameter for customizing policy templates
- type PolicyTemplateParam struct {
- Name string `json:"name"`
- Type string `json:"type"`
- Description string `json:"description"`
- Required bool `json:"required"`
- DefaultValue string `json:"default_value,omitempty"`
- Example string `json:"example,omitempty"`
- }
- // GetAllPolicyTemplates returns all available policy templates with metadata
- func (t *S3PolicyTemplates) GetAllPolicyTemplates() []PolicyTemplateDefinition {
- return []PolicyTemplateDefinition{
- {
- Name: "S3ReadOnlyAccess",
- Description: "Provides read-only access to all S3 buckets and objects",
- Category: "Basic Access",
- UseCase: "Data consumers, backup services, monitoring applications",
- Policy: t.GetS3ReadOnlyPolicy(),
- },
- {
- Name: "S3WriteOnlyAccess",
- Description: "Provides write-only access to all S3 buckets and objects",
- Category: "Basic Access",
- UseCase: "Data ingestion services, backup applications",
- Policy: t.GetS3WriteOnlyPolicy(),
- },
- {
- Name: "S3AdminAccess",
- Description: "Provides full administrative access to all S3 resources",
- Category: "Administrative",
- UseCase: "S3 administrators, service accounts with full control",
- Policy: t.GetS3AdminPolicy(),
- },
- {
- Name: "BucketSpecificRead",
- Description: "Provides read-only access to a specific bucket",
- Category: "Bucket-Specific",
- UseCase: "Applications that need access to specific data sets",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket to grant access to",
- Required: true,
- Example: "my-data-bucket",
- },
- },
- Policy: t.GetBucketSpecificReadPolicy("${bucketName}"),
- },
- {
- Name: "BucketSpecificWrite",
- Description: "Provides write-only access to a specific bucket",
- Category: "Bucket-Specific",
- UseCase: "Upload services, data ingestion for specific datasets",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket to grant access to",
- Required: true,
- Example: "my-upload-bucket",
- },
- },
- Policy: t.GetBucketSpecificWritePolicy("${bucketName}"),
- },
- {
- Name: "PathBasedAccess",
- Description: "Restricts access to a specific path/prefix within a bucket",
- Category: "Path-Restricted",
- UseCase: "Multi-tenant applications, user-specific directories",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket",
- Required: true,
- Example: "shared-bucket",
- },
- {
- Name: "pathPrefix",
- Type: "string",
- Description: "Path prefix to restrict access to",
- Required: true,
- Example: "user123/documents",
- },
- },
- Policy: t.GetPathBasedAccessPolicy("${bucketName}", "${pathPrefix}"),
- },
- {
- Name: "IPRestrictedAccess",
- Description: "Allows access only from specific IP addresses or ranges",
- Category: "Security",
- UseCase: "Corporate networks, office-based access, VPN restrictions",
- Parameters: []PolicyTemplateParam{
- {
- Name: "allowedCIDRs",
- Type: "array",
- Description: "List of allowed IP addresses or CIDR ranges",
- Required: true,
- Example: "[\"192.168.1.0/24\", \"10.0.0.0/8\"]",
- },
- },
- Policy: t.GetIPRestrictedPolicy([]string{"${allowedCIDRs}"}),
- },
- {
- Name: "MultipartUploadOnly",
- Description: "Allows only multipart upload operations on a specific bucket",
- Category: "Upload-Specific",
- UseCase: "Large file upload services, streaming applications",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket for multipart uploads",
- Required: true,
- Example: "large-files-bucket",
- },
- },
- Policy: t.GetMultipartUploadPolicy("${bucketName}"),
- },
- {
- Name: "PresignedURLAccess",
- Description: "Policy for generating and using presigned URLs",
- Category: "Presigned URLs",
- UseCase: "Frontend applications, temporary file sharing",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket for presigned URL access",
- Required: true,
- Example: "shared-files-bucket",
- },
- },
- Policy: t.GetPresignedURLPolicy("${bucketName}"),
- },
- {
- Name: "ContentTypeRestricted",
- Description: "Restricts uploads to specific content types",
- Category: "Content Control",
- UseCase: "Image galleries, document repositories, media libraries",
- Parameters: []PolicyTemplateParam{
- {
- Name: "bucketName",
- Type: "string",
- Description: "Name of the S3 bucket",
- Required: true,
- Example: "media-bucket",
- },
- {
- Name: "allowedContentTypes",
- Type: "array",
- Description: "List of allowed MIME content types",
- Required: true,
- Example: "[\"image/jpeg\", \"image/png\", \"video/mp4\"]",
- },
- },
- Policy: t.GetContentTypeRestrictedPolicy("${bucketName}", []string{"${allowedContentTypes}"}),
- },
- {
- Name: "DenyDeleteAccess",
- Description: "Allows all operations except delete (immutable storage)",
- Category: "Data Protection",
- UseCase: "Compliance storage, audit logs, backup retention",
- Policy: t.GetDenyDeletePolicy(),
- },
- }
- }
- // GetPolicyTemplateByName returns a specific policy template by name
- func (t *S3PolicyTemplates) GetPolicyTemplateByName(name string) *PolicyTemplateDefinition {
- templates := t.GetAllPolicyTemplates()
- for _, template := range templates {
- if template.Name == name {
- return &template
- }
- }
- return nil
- }
- // GetPolicyTemplatesByCategory returns all policy templates in a specific category
- func (t *S3PolicyTemplates) GetPolicyTemplatesByCategory(category string) []PolicyTemplateDefinition {
- var result []PolicyTemplateDefinition
- templates := t.GetAllPolicyTemplates()
- for _, template := range templates {
- if template.Category == category {
- result = append(result, template)
- }
- }
- return result
- }
|