examples.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. //go:build ignore
  2. // +build ignore
  3. package policy_engine
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. )
  8. // This file contains examples and documentation for the policy engine
  9. // ExampleIdentityJSON shows the existing identities.json format (unchanged)
  10. var ExampleIdentityJSON = `{
  11. "identities": [
  12. {
  13. "name": "user1",
  14. "credentials": [
  15. {
  16. "accessKey": "AKIAIOSFODNN7EXAMPLE",
  17. "secretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  18. }
  19. ],
  20. "actions": [
  21. "Read:bucket1/*",
  22. "Write:bucket1/*",
  23. "Admin:bucket2"
  24. ]
  25. },
  26. {
  27. "name": "readonly-user",
  28. "credentials": [
  29. {
  30. "accessKey": "AKIAI44QH8DHBEXAMPLE",
  31. "secretKey": "je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY"
  32. }
  33. ],
  34. "actions": [
  35. "Read:bucket1/*",
  36. "List:bucket1"
  37. ]
  38. }
  39. ]
  40. }`
  41. // ExampleBucketPolicy shows an AWS S3 bucket policy with conditions
  42. var ExampleBucketPolicy = `{
  43. "Version": "2012-10-17",
  44. "Statement": [
  45. {
  46. "Sid": "AllowGetObjectFromSpecificIP",
  47. "Effect": "Allow",
  48. "Principal": "*",
  49. "Action": "s3:GetObject",
  50. "Resource": "arn:aws:s3:::my-bucket/*",
  51. "Condition": {
  52. "IpAddress": {
  53. "aws:SourceIp": "192.168.1.0/24"
  54. }
  55. }
  56. },
  57. {
  58. "Sid": "AllowPutObjectWithSSL",
  59. "Effect": "Allow",
  60. "Principal": "*",
  61. "Action": "s3:PutObject",
  62. "Resource": "arn:aws:s3:::my-bucket/*",
  63. "Condition": {
  64. "Bool": {
  65. "aws:SecureTransport": "true"
  66. }
  67. }
  68. },
  69. {
  70. "Sid": "DenyDeleteFromProduction",
  71. "Effect": "Deny",
  72. "Principal": "*",
  73. "Action": "s3:DeleteObject",
  74. "Resource": "arn:aws:s3:::my-bucket/production/*"
  75. }
  76. ]
  77. }`
  78. // ExampleTimeBasedPolicy shows a policy with time-based conditions
  79. var ExampleTimeBasedPolicy = `{
  80. "Version": "2012-10-17",
  81. "Statement": [
  82. {
  83. "Sid": "AllowAccessDuringBusinessHours",
  84. "Effect": "Allow",
  85. "Principal": "*",
  86. "Action": ["s3:GetObject", "s3:PutObject"],
  87. "Resource": "arn:aws:s3:::my-bucket/*",
  88. "Condition": {
  89. "DateGreaterThan": {
  90. "aws:RequestTime": "2023-01-01T08:00:00Z"
  91. },
  92. "DateLessThan": {
  93. "aws:RequestTime": "2023-12-31T18:00:00Z"
  94. }
  95. }
  96. }
  97. ]
  98. }`
  99. // ExampleIPRestrictedPolicy shows a policy with IP restrictions
  100. var ExampleIPRestrictedPolicy = `{
  101. "Version": "2012-10-17",
  102. "Statement": [
  103. {
  104. "Sid": "AllowFromOfficeNetwork",
  105. "Effect": "Allow",
  106. "Principal": "*",
  107. "Action": "s3:*",
  108. "Resource": [
  109. "arn:aws:s3:::my-bucket",
  110. "arn:aws:s3:::my-bucket/*"
  111. ],
  112. "Condition": {
  113. "IpAddress": {
  114. "aws:SourceIp": [
  115. "203.0.113.0/24",
  116. "198.51.100.0/24"
  117. ]
  118. }
  119. }
  120. },
  121. {
  122. "Sid": "DenyFromRestrictedIPs",
  123. "Effect": "Deny",
  124. "Principal": "*",
  125. "Action": "*",
  126. "Resource": "*",
  127. "Condition": {
  128. "IpAddress": {
  129. "aws:SourceIp": [
  130. "192.0.2.0/24"
  131. ]
  132. }
  133. }
  134. }
  135. ]
  136. }`
  137. // ExamplePublicReadPolicy shows a policy for public read access
  138. var ExamplePublicReadPolicy = `{
  139. "Version": "2012-10-17",
  140. "Statement": [
  141. {
  142. "Sid": "PublicReadGetObject",
  143. "Effect": "Allow",
  144. "Principal": "*",
  145. "Action": "s3:GetObject",
  146. "Resource": "arn:aws:s3:::my-public-bucket/*"
  147. }
  148. ]
  149. }`
  150. // ExampleCORSPolicy shows a policy with CORS-related conditions
  151. var ExampleCORSPolicy = `{
  152. "Version": "2012-10-17",
  153. "Statement": [
  154. {
  155. "Sid": "AllowCrossOriginRequests",
  156. "Effect": "Allow",
  157. "Principal": "*",
  158. "Action": ["s3:GetObject", "s3:PutObject"],
  159. "Resource": "arn:aws:s3:::my-bucket/*",
  160. "Condition": {
  161. "StringLike": {
  162. "aws:Referer": [
  163. "https://example.com/*",
  164. "https://*.example.com/*"
  165. ]
  166. }
  167. }
  168. }
  169. ]
  170. }`
  171. // ExampleUserAgentPolicy shows a policy with user agent restrictions
  172. var ExampleUserAgentPolicy = `{
  173. "Version": "2012-10-17",
  174. "Statement": [
  175. {
  176. "Sid": "AllowSpecificUserAgents",
  177. "Effect": "Allow",
  178. "Principal": "*",
  179. "Action": "s3:GetObject",
  180. "Resource": "arn:aws:s3:::my-bucket/*",
  181. "Condition": {
  182. "StringLike": {
  183. "aws:UserAgent": [
  184. "MyApp/*",
  185. "curl/*"
  186. ]
  187. }
  188. }
  189. }
  190. ]
  191. }`
  192. // ExamplePrefixBasedPolicy shows a policy with prefix-based access
  193. var ExamplePrefixBasedPolicy = `{
  194. "Version": "2012-10-17",
  195. "Statement": [
  196. {
  197. "Sid": "AllowUserFolderAccess",
  198. "Effect": "Allow",
  199. "Principal": "*",
  200. "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
  201. "Resource": "arn:aws:s3:::my-bucket/${aws:username}/*",
  202. "Condition": {
  203. "StringEquals": {
  204. "s3:prefix": "${aws:username}/"
  205. }
  206. }
  207. }
  208. ]
  209. }`
  210. // ExampleMultiStatementPolicy shows a complex policy with multiple statements
  211. var ExampleMultiStatementPolicy = `{
  212. "Version": "2012-10-17",
  213. "Statement": [
  214. {
  215. "Sid": "AllowListBucket",
  216. "Effect": "Allow",
  217. "Principal": "*",
  218. "Action": "s3:ListBucket",
  219. "Resource": "arn:aws:s3:::my-bucket",
  220. "Condition": {
  221. "StringEquals": {
  222. "s3:prefix": "public/"
  223. }
  224. }
  225. },
  226. {
  227. "Sid": "AllowGetPublicObjects",
  228. "Effect": "Allow",
  229. "Principal": "*",
  230. "Action": "s3:GetObject",
  231. "Resource": "arn:aws:s3:::my-bucket/public/*"
  232. },
  233. {
  234. "Sid": "AllowAuthenticatedUpload",
  235. "Effect": "Allow",
  236. "Principal": "*",
  237. "Action": "s3:PutObject",
  238. "Resource": "arn:aws:s3:::my-bucket/uploads/*",
  239. "Condition": {
  240. "StringEquals": {
  241. "s3:x-amz-acl": "private"
  242. }
  243. }
  244. },
  245. {
  246. "Sid": "DenyInsecureConnections",
  247. "Effect": "Deny",
  248. "Principal": "*",
  249. "Action": "s3:*",
  250. "Resource": [
  251. "arn:aws:s3:::my-bucket",
  252. "arn:aws:s3:::my-bucket/*"
  253. ],
  254. "Condition": {
  255. "Bool": {
  256. "aws:SecureTransport": "false"
  257. }
  258. }
  259. }
  260. ]
  261. }`
  262. // GetAllExamples returns all example policies
  263. func GetAllExamples() map[string]string {
  264. return map[string]string{
  265. "basic-bucket-policy": ExampleBucketPolicy,
  266. "time-based-policy": ExampleTimeBasedPolicy,
  267. "ip-restricted-policy": ExampleIPRestrictedPolicy,
  268. "public-read-policy": ExamplePublicReadPolicy,
  269. "cors-policy": ExampleCORSPolicy,
  270. "user-agent-policy": ExampleUserAgentPolicy,
  271. "prefix-based-policy": ExamplePrefixBasedPolicy,
  272. "multi-statement-policy": ExampleMultiStatementPolicy,
  273. }
  274. }
  275. // ValidateExamplePolicies validates all example policies
  276. func ValidateExamplePolicies() error {
  277. examples := GetAllExamples()
  278. for name, policyJSON := range examples {
  279. _, err := ParsePolicy(policyJSON)
  280. if err != nil {
  281. return fmt.Errorf("invalid example policy %s: %v", name, err)
  282. }
  283. }
  284. return nil
  285. }
  286. // GetExamplePolicy returns a specific example policy
  287. func GetExamplePolicy(name string) (string, error) {
  288. examples := GetAllExamples()
  289. policy, exists := examples[name]
  290. if !exists {
  291. return "", fmt.Errorf("example policy %s not found", name)
  292. }
  293. return policy, nil
  294. }
  295. // CreateExamplePolicyDocument creates a PolicyDocument from an example
  296. func CreateExamplePolicyDocument(name string) (*PolicyDocument, error) {
  297. policyJSON, err := GetExamplePolicy(name)
  298. if err != nil {
  299. return nil, err
  300. }
  301. return ParsePolicy(policyJSON)
  302. }
  303. // PrintExamplePolicyPretty prints an example policy in pretty format
  304. func PrintExamplePolicyPretty(name string) error {
  305. policyJSON, err := GetExamplePolicy(name)
  306. if err != nil {
  307. return err
  308. }
  309. var policy interface{}
  310. if err := json.Unmarshal([]byte(policyJSON), &policy); err != nil {
  311. return err
  312. }
  313. prettyJSON, err := json.MarshalIndent(policy, "", " ")
  314. if err != nil {
  315. return err
  316. }
  317. fmt.Printf("Example Policy: %s\n", name)
  318. fmt.Printf("================\n")
  319. fmt.Println(string(prettyJSON))
  320. return nil
  321. }
  322. // ExampleUsage demonstrates how to use the policy engine
  323. func ExampleUsage() {
  324. // Create a new policy engine
  325. engine := NewPolicyEngine()
  326. // Set a bucket policy
  327. policyJSON := ExampleBucketPolicy
  328. err := engine.SetBucketPolicy("my-bucket", policyJSON)
  329. if err != nil {
  330. fmt.Printf("Error setting bucket policy: %v\n", err)
  331. return
  332. }
  333. // Evaluate a policy
  334. args := &PolicyEvaluationArgs{
  335. Action: "s3:GetObject",
  336. Resource: "arn:aws:s3:::my-bucket/test-object",
  337. Principal: "*",
  338. Conditions: map[string][]string{
  339. "aws:SourceIp": {"192.168.1.100"},
  340. },
  341. }
  342. result := engine.EvaluatePolicy("my-bucket", args)
  343. switch result {
  344. case PolicyResultAllow:
  345. fmt.Println("Access allowed")
  346. case PolicyResultDeny:
  347. fmt.Println("Access denied")
  348. case PolicyResultIndeterminate:
  349. fmt.Println("Access indeterminate")
  350. }
  351. }
  352. // ExampleLegacyIntegration demonstrates backward compatibility
  353. func ExampleLegacyIntegration() {
  354. // Legacy identity actions
  355. legacyActions := []string{
  356. "Read:bucket1/*",
  357. "Write:bucket1/uploads/*",
  358. "Admin:bucket2",
  359. }
  360. // Convert to policy
  361. policy, err := ConvertIdentityToPolicy(legacyActions, "bucket1")
  362. if err != nil {
  363. fmt.Printf("Error converting identity to policy: %v\n", err)
  364. return
  365. }
  366. // Create policy-backed IAM
  367. policyIAM := NewPolicyBackedIAM()
  368. // Set the converted policy
  369. policyJSON, _ := json.MarshalIndent(policy, "", " ")
  370. err = policyIAM.SetBucketPolicy("bucket1", string(policyJSON))
  371. if err != nil {
  372. fmt.Printf("Error setting bucket policy: %v\n", err)
  373. return
  374. }
  375. fmt.Println("Legacy identity successfully converted to AWS S3 policy")
  376. }
  377. // ExampleConditions demonstrates various condition types
  378. func ExampleConditions() {
  379. examples := map[string]string{
  380. "StringEquals": `"StringEquals": {"s3:prefix": "documents/"}`,
  381. "StringLike": `"StringLike": {"aws:UserAgent": "MyApp/*"}`,
  382. "NumericEquals": `"NumericEquals": {"s3:max-keys": "10"}`,
  383. "NumericLessThan": `"NumericLessThan": {"s3:max-keys": "1000"}`,
  384. "DateGreaterThan": `"DateGreaterThan": {"aws:RequestTime": "2023-01-01T00:00:00Z"}`,
  385. "DateLessThan": `"DateLessThan": {"aws:RequestTime": "2023-12-31T23:59:59Z"}`,
  386. "IpAddress": `"IpAddress": {"aws:SourceIp": "192.168.1.0/24"}`,
  387. "NotIpAddress": `"NotIpAddress": {"aws:SourceIp": "10.0.0.0/8"}`,
  388. "Bool": `"Bool": {"aws:SecureTransport": "true"}`,
  389. "Null": `"Null": {"s3:x-amz-server-side-encryption": "false"}`,
  390. }
  391. fmt.Println("Supported Condition Operators:")
  392. fmt.Println("==============================")
  393. for operator, example := range examples {
  394. fmt.Printf("%s: %s\n", operator, example)
  395. }
  396. }
  397. // ExampleMigrationStrategy demonstrates migration from legacy to policy-based system
  398. func ExampleMigrationStrategy() {
  399. fmt.Println("Migration Strategy:")
  400. fmt.Println("==================")
  401. fmt.Println("1. Keep existing identities.json unchanged")
  402. fmt.Println("2. Legacy actions are automatically converted to AWS policies internally")
  403. fmt.Println("3. Add bucket policies for advanced features:")
  404. fmt.Println(" - IP restrictions")
  405. fmt.Println(" - Time-based access")
  406. fmt.Println(" - SSL-only access")
  407. fmt.Println(" - User agent restrictions")
  408. fmt.Println("4. Policy evaluation precedence:")
  409. fmt.Println(" - Explicit Deny (highest priority)")
  410. fmt.Println(" - Explicit Allow")
  411. fmt.Println(" - Default Deny (lowest priority)")
  412. }
  413. // PrintAllExamples prints all example policies
  414. func PrintAllExamples() {
  415. examples := GetAllExamples()
  416. for name := range examples {
  417. fmt.Printf("\n")
  418. PrintExamplePolicyPretty(name)
  419. fmt.Printf("\n")
  420. }
  421. }