aboutsummaryrefslogtreecommitdiff
path: root/weed/s3api/policy_engine/examples.go
diff options
context:
space:
mode:
Diffstat (limited to 'weed/s3api/policy_engine/examples.go')
-rw-r--r--weed/s3api/policy_engine/examples.go463
1 files changed, 463 insertions, 0 deletions
diff --git a/weed/s3api/policy_engine/examples.go b/weed/s3api/policy_engine/examples.go
new file mode 100644
index 000000000..6f14127f3
--- /dev/null
+++ b/weed/s3api/policy_engine/examples.go
@@ -0,0 +1,463 @@
+//go:build ignore
+// +build ignore
+
+package policy_engine
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// This file contains examples and documentation for the policy engine
+
+// ExampleIdentityJSON shows the existing identities.json format (unchanged)
+var ExampleIdentityJSON = `{
+ "identities": [
+ {
+ "name": "user1",
+ "credentials": [
+ {
+ "accessKey": "AKIAIOSFODNN7EXAMPLE",
+ "secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
+ }
+ ],
+ "actions": [
+ "Read:bucket1/*",
+ "Write:bucket1/*",
+ "Admin:bucket2"
+ ]
+ },
+ {
+ "name": "readonly-user",
+ "credentials": [
+ {
+ "accessKey": "AKIAI44QH8DHBEXAMPLE",
+ "secretKey": "je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY"
+ }
+ ],
+ "actions": [
+ "Read:bucket1/*",
+ "List:bucket1"
+ ]
+ }
+ ]
+}`
+
+// ExampleBucketPolicy shows an AWS S3 bucket policy with conditions
+var ExampleBucketPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowGetObjectFromSpecificIP",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:GetObject",
+ "Resource": "arn:aws:s3:::my-bucket/*",
+ "Condition": {
+ "IpAddress": {
+ "aws:SourceIp": "192.168.1.0/24"
+ }
+ }
+ },
+ {
+ "Sid": "AllowPutObjectWithSSL",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:PutObject",
+ "Resource": "arn:aws:s3:::my-bucket/*",
+ "Condition": {
+ "Bool": {
+ "aws:SecureTransport": "true"
+ }
+ }
+ },
+ {
+ "Sid": "DenyDeleteFromProduction",
+ "Effect": "Deny",
+ "Principal": "*",
+ "Action": "s3:DeleteObject",
+ "Resource": "arn:aws:s3:::my-bucket/production/*"
+ }
+ ]
+}`
+
+// ExampleTimeBasedPolicy shows a policy with time-based conditions
+var ExampleTimeBasedPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowAccessDuringBusinessHours",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": ["s3:GetObject", "s3:PutObject"],
+ "Resource": "arn:aws:s3:::my-bucket/*",
+ "Condition": {
+ "DateGreaterThan": {
+ "aws:RequestTime": "2023-01-01T08:00:00Z"
+ },
+ "DateLessThan": {
+ "aws:RequestTime": "2023-12-31T18:00:00Z"
+ }
+ }
+ }
+ ]
+}`
+
+// ExampleIPRestrictedPolicy shows a policy with IP restrictions
+var ExampleIPRestrictedPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowFromOfficeNetwork",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:*",
+ "Resource": [
+ "arn:aws:s3:::my-bucket",
+ "arn:aws:s3:::my-bucket/*"
+ ],
+ "Condition": {
+ "IpAddress": {
+ "aws:SourceIp": [
+ "203.0.113.0/24",
+ "198.51.100.0/24"
+ ]
+ }
+ }
+ },
+ {
+ "Sid": "DenyFromRestrictedIPs",
+ "Effect": "Deny",
+ "Principal": "*",
+ "Action": "*",
+ "Resource": "*",
+ "Condition": {
+ "IpAddress": {
+ "aws:SourceIp": [
+ "192.0.2.0/24"
+ ]
+ }
+ }
+ }
+ ]
+}`
+
+// ExamplePublicReadPolicy shows a policy for public read access
+var ExamplePublicReadPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "PublicReadGetObject",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:GetObject",
+ "Resource": "arn:aws:s3:::my-public-bucket/*"
+ }
+ ]
+}`
+
+// ExampleCORSPolicy shows a policy with CORS-related conditions
+var ExampleCORSPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowCrossOriginRequests",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": ["s3:GetObject", "s3:PutObject"],
+ "Resource": "arn:aws:s3:::my-bucket/*",
+ "Condition": {
+ "StringLike": {
+ "aws:Referer": [
+ "https://example.com/*",
+ "https://*.example.com/*"
+ ]
+ }
+ }
+ }
+ ]
+}`
+
+// ExampleUserAgentPolicy shows a policy with user agent restrictions
+var ExampleUserAgentPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowSpecificUserAgents",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:GetObject",
+ "Resource": "arn:aws:s3:::my-bucket/*",
+ "Condition": {
+ "StringLike": {
+ "aws:UserAgent": [
+ "MyApp/*",
+ "curl/*"
+ ]
+ }
+ }
+ }
+ ]
+}`
+
+// ExamplePrefixBasedPolicy shows a policy with prefix-based access
+var ExamplePrefixBasedPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowUserFolderAccess",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
+ "Resource": "arn:aws:s3:::my-bucket/${aws:username}/*",
+ "Condition": {
+ "StringEquals": {
+ "s3:prefix": "${aws:username}/"
+ }
+ }
+ }
+ ]
+}`
+
+// ExampleMultiStatementPolicy shows a complex policy with multiple statements
+var ExampleMultiStatementPolicy = `{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "AllowListBucket",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:ListBucket",
+ "Resource": "arn:aws:s3:::my-bucket",
+ "Condition": {
+ "StringEquals": {
+ "s3:prefix": "public/"
+ }
+ }
+ },
+ {
+ "Sid": "AllowGetPublicObjects",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:GetObject",
+ "Resource": "arn:aws:s3:::my-bucket/public/*"
+ },
+ {
+ "Sid": "AllowAuthenticatedUpload",
+ "Effect": "Allow",
+ "Principal": "*",
+ "Action": "s3:PutObject",
+ "Resource": "arn:aws:s3:::my-bucket/uploads/*",
+ "Condition": {
+ "StringEquals": {
+ "s3:x-amz-acl": "private"
+ }
+ }
+ },
+ {
+ "Sid": "DenyInsecureConnections",
+ "Effect": "Deny",
+ "Principal": "*",
+ "Action": "s3:*",
+ "Resource": [
+ "arn:aws:s3:::my-bucket",
+ "arn:aws:s3:::my-bucket/*"
+ ],
+ "Condition": {
+ "Bool": {
+ "aws:SecureTransport": "false"
+ }
+ }
+ }
+ ]
+}`
+
+// GetAllExamples returns all example policies
+func GetAllExamples() map[string]string {
+ return map[string]string{
+ "basic-bucket-policy": ExampleBucketPolicy,
+ "time-based-policy": ExampleTimeBasedPolicy,
+ "ip-restricted-policy": ExampleIPRestrictedPolicy,
+ "public-read-policy": ExamplePublicReadPolicy,
+ "cors-policy": ExampleCORSPolicy,
+ "user-agent-policy": ExampleUserAgentPolicy,
+ "prefix-based-policy": ExamplePrefixBasedPolicy,
+ "multi-statement-policy": ExampleMultiStatementPolicy,
+ }
+}
+
+// ValidateExamplePolicies validates all example policies
+func ValidateExamplePolicies() error {
+ examples := GetAllExamples()
+
+ for name, policyJSON := range examples {
+ _, err := ParsePolicy(policyJSON)
+ if err != nil {
+ return fmt.Errorf("invalid example policy %s: %v", name, err)
+ }
+ }
+
+ return nil
+}
+
+// GetExamplePolicy returns a specific example policy
+func GetExamplePolicy(name string) (string, error) {
+ examples := GetAllExamples()
+
+ policy, exists := examples[name]
+ if !exists {
+ return "", fmt.Errorf("example policy %s not found", name)
+ }
+
+ return policy, nil
+}
+
+// CreateExamplePolicyDocument creates a PolicyDocument from an example
+func CreateExamplePolicyDocument(name string) (*PolicyDocument, error) {
+ policyJSON, err := GetExamplePolicy(name)
+ if err != nil {
+ return nil, err
+ }
+
+ return ParsePolicy(policyJSON)
+}
+
+// PrintExamplePolicyPretty prints an example policy in pretty format
+func PrintExamplePolicyPretty(name string) error {
+ policyJSON, err := GetExamplePolicy(name)
+ if err != nil {
+ return err
+ }
+
+ var policy interface{}
+ if err := json.Unmarshal([]byte(policyJSON), &policy); err != nil {
+ return err
+ }
+
+ prettyJSON, err := json.MarshalIndent(policy, "", " ")
+ if err != nil {
+ return err
+ }
+
+ fmt.Printf("Example Policy: %s\n", name)
+ fmt.Printf("================\n")
+ fmt.Println(string(prettyJSON))
+
+ return nil
+}
+
+// ExampleUsage demonstrates how to use the policy engine
+func ExampleUsage() {
+ // Create a new policy engine
+ engine := NewPolicyEngine()
+
+ // Set a bucket policy
+ policyJSON := ExampleBucketPolicy
+ err := engine.SetBucketPolicy("my-bucket", policyJSON)
+ if err != nil {
+ fmt.Printf("Error setting bucket policy: %v\n", err)
+ return
+ }
+
+ // Evaluate a policy
+ args := &PolicyEvaluationArgs{
+ Action: "s3:GetObject",
+ Resource: "arn:aws:s3:::my-bucket/test-object",
+ Principal: "*",
+ Conditions: map[string][]string{
+ "aws:SourceIp": {"192.168.1.100"},
+ },
+ }
+
+ result := engine.EvaluatePolicy("my-bucket", args)
+
+ switch result {
+ case PolicyResultAllow:
+ fmt.Println("Access allowed")
+ case PolicyResultDeny:
+ fmt.Println("Access denied")
+ case PolicyResultIndeterminate:
+ fmt.Println("Access indeterminate")
+ }
+}
+
+// ExampleLegacyIntegration demonstrates backward compatibility
+func ExampleLegacyIntegration() {
+ // Legacy identity actions
+ legacyActions := []string{
+ "Read:bucket1/*",
+ "Write:bucket1/uploads/*",
+ "Admin:bucket2",
+ }
+
+ // Convert to policy
+ policy, err := ConvertIdentityToPolicy(legacyActions, "bucket1")
+ if err != nil {
+ fmt.Printf("Error converting identity to policy: %v\n", err)
+ return
+ }
+
+ // Create policy-backed IAM
+ policyIAM := NewPolicyBackedIAM()
+
+ // Set the converted policy
+ policyJSON, _ := json.MarshalIndent(policy, "", " ")
+ err = policyIAM.SetBucketPolicy("bucket1", string(policyJSON))
+ if err != nil {
+ fmt.Printf("Error setting bucket policy: %v\n", err)
+ return
+ }
+
+ fmt.Println("Legacy identity successfully converted to AWS S3 policy")
+}
+
+// ExampleConditions demonstrates various condition types
+func ExampleConditions() {
+ examples := map[string]string{
+ "StringEquals": `"StringEquals": {"s3:prefix": "documents/"}`,
+ "StringLike": `"StringLike": {"aws:UserAgent": "MyApp/*"}`,
+ "NumericEquals": `"NumericEquals": {"s3:max-keys": "10"}`,
+ "NumericLessThan": `"NumericLessThan": {"s3:max-keys": "1000"}`,
+ "DateGreaterThan": `"DateGreaterThan": {"aws:RequestTime": "2023-01-01T00:00:00Z"}`,
+ "DateLessThan": `"DateLessThan": {"aws:RequestTime": "2023-12-31T23:59:59Z"}`,
+ "IpAddress": `"IpAddress": {"aws:SourceIp": "192.168.1.0/24"}`,
+ "NotIpAddress": `"NotIpAddress": {"aws:SourceIp": "10.0.0.0/8"}`,
+ "Bool": `"Bool": {"aws:SecureTransport": "true"}`,
+ "Null": `"Null": {"s3:x-amz-server-side-encryption": "false"}`,
+ }
+
+ fmt.Println("Supported Condition Operators:")
+ fmt.Println("==============================")
+
+ for operator, example := range examples {
+ fmt.Printf("%s: %s\n", operator, example)
+ }
+}
+
+// ExampleMigrationStrategy demonstrates migration from legacy to policy-based system
+func ExampleMigrationStrategy() {
+ fmt.Println("Migration Strategy:")
+ fmt.Println("==================")
+ fmt.Println("1. Keep existing identities.json unchanged")
+ fmt.Println("2. Legacy actions are automatically converted to AWS policies internally")
+ fmt.Println("3. Add bucket policies for advanced features:")
+ fmt.Println(" - IP restrictions")
+ fmt.Println(" - Time-based access")
+ fmt.Println(" - SSL-only access")
+ fmt.Println(" - User agent restrictions")
+ fmt.Println("4. Policy evaluation precedence:")
+ fmt.Println(" - Explicit Deny (highest priority)")
+ fmt.Println(" - Explicit Allow")
+ fmt.Println(" - Default Deny (lowest priority)")
+}
+
+// PrintAllExamples prints all example policies
+func PrintAllExamples() {
+ examples := GetAllExamples()
+
+ for name := range examples {
+ fmt.Printf("\n")
+ PrintExamplePolicyPretty(name)
+ fmt.Printf("\n")
+ }
+}