From b5dcf463aca4900cf528dbd635e5518c1f11dc2e Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 15 May 2024 10:23:35 +0100 Subject: [PATCH 1/3] Add GetTableMetadata to Athena read policy. This is required by later versions of the R noctua package, a dependency of Rdbtools. --- examples/iam_policy.json | 1 + iam_builder/templates.py | 300 +++++++----------- tests/expected_policy/all_config.json | 1 + tests/expected_policy/athena_full_access.json | 1 + tests/expected_policy/athena_read_only.json | 1 + tests/expected_policy/athena_two_dumps.json | 1 + 6 files changed, 128 insertions(+), 177 deletions(-) diff --git a/examples/iam_policy.json b/examples/iam_policy.json index b85da93..eded722 100644 --- a/examples/iam_policy.json +++ b/examples/iam_policy.json @@ -80,6 +80,7 @@ "athena:GetNamespaces", "athena:GetTable", "athena:GetTables", + "athena:GetTableMetadata", "athena:RunQuery", "glue:GetDatabase", "glue:GetDatabases", diff --git a/iam_builder/templates.py b/iam_builder/templates.py index f57cacd..3dc4ed6 100755 --- a/iam_builder/templates.py +++ b/iam_builder/templates.py @@ -1,10 +1,7 @@ # Formatted to match JSON IAM policy - so purposefully # not matching standard Python line break conventions -iam_base_template = { - "Version": "2012-10-17", - "Statement": [] -} +iam_base_template = {"Version": "2012-10-17", "Statement": []} # Standard segments of iam policy that don't need parameters @@ -29,11 +26,9 @@ "glue:UpdateTable", "glue:CreateUserDefinedFunction", "glue:DeleteUserDefinedFunction", - "glue:UpdateUserDefinedFunction" + "glue:UpdateUserDefinedFunction", ], - "Resource": [ - "*" - ] + "Resource": ["*"], } ], "glue_job": [ @@ -52,11 +47,9 @@ "glue:UpdateJob", "glue:ListJobs", "glue:BatchGetJobs", - "glue:GetJobBookmark" + "glue:GetJobBookmark", ], - "Resource": [ - "*" - ] + "Resource": ["*"], }, { "Sid": "CanGetLogs", @@ -66,11 +59,9 @@ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", - "logs:DescribeLogStreams" + "logs:DescribeLogStreams", ], - "Resource": [ - "arn:aws:logs:*:*:/aws-glue/*" - ] + "Resource": ["arn:aws:logs:*:*:/aws-glue/*"], }, { "Sid": "CanGetCloudWatchLogs", @@ -78,38 +69,29 @@ "Action": [ "cloudwatch:PutMetricData", "cloudwatch:GetMetricData", - "cloudwatch:ListDashboards" + "cloudwatch:ListDashboards", ], - "Resource": [ - "*" - ] + "Resource": ["*"], }, { "Sid": "CanReadGlueStuff", "Effect": "Allow", - "Action": [ - "s3:GetObject", - "s3:PutObject" - ], + "Action": ["s3:GetObject", "s3:PutObject"], "Resource": [ "arn:aws:s3:::aws-glue-*/*", "arn:aws:s3:::*/*aws-glue-*/*", - "arn:aws:s3:::aws-glue-*" - ] - } + "arn:aws:s3:::aws-glue-*", + ], + }, ], "decrypt_statement": [ { "Sid": "allowDecrypt", "Effect": "Allow", - "Action": [ - "kms:Decrypt" - ], - "Resource": [ - "arn:aws:kms:::key/*" - ] + "Action": ["kms:Decrypt"], + "Resource": ["arn:aws:kms:::key/*"], } - ] + ], } @@ -123,157 +105,128 @@ def get_athena_read_access(dump_bucket: list) -> dict: """ # prepare segments that depend on dump bucket name allow_list_bucket_resources = ["arn:aws:s3:::moj-analytics-lookup-tables"] - allow_list_bucket_resources.extend([ - "arn:aws:s3:::" + bucket for bucket in dump_bucket - ]) + allow_list_bucket_resources.extend( + ["arn:aws:s3:::" + bucket for bucket in dump_bucket] + ) allow_get_put_delete_resources = [ "arn:aws:s3:::" + bucket + "/${aws:userid}/*" for bucket in dump_bucket ] # insert prepared sections into full iam lookup for Athena reading athena_read_access = [ - { - "Sid": "AllowListAllMyBuckets", - "Effect": "Allow", - "Action": [ - "s3:GetBucketLocation", - "s3:ListAllMyBuckets" - ], - "Resource": [ - "*" - ] - }, - { - "Sid": "AllowListBucket", - "Effect": "Allow", - "Action": [ - "s3:ListBucket" - ], - "Resource": allow_list_bucket_resources - }, - { - "Sid": "AllowGetObject", - "Effect": "Allow", - "Action": [ - "s3:GetObject" - ], - "Resource": [ - "arn:aws:s3:::moj-analytics-lookup-tables/*" - ] - }, - { - "Sid": "AllowGetPutObject", - "Effect": "Allow", - "Action": [ - "s3:GetObject", - "s3:PutObject" - ], - "Resource": [ - "arn:aws:s3:::aws-athena-query-results-*" - ] - }, - { - "Sid": "AllowGetPutDeleteObject", - "Effect": "Allow", - "Action": [ - "s3:GetObject", - "s3:PutObject", - "s3:DeleteObject" - ], - "Resource": allow_get_put_delete_resources - }, - { - "Sid": "AllowReadAthenaGlue", - "Effect": "Allow", - "Action": [ - "athena:BatchGetNamedQuery", - "athena:BatchGetQueryExecution", - "athena:GetNamedQuery", - "athena:GetQueryExecution", - "athena:GetQueryResults", - "athena:GetQueryResultsStream", - "athena:GetWorkGroup", - "athena:ListNamedQueries", - "athena:ListQueryExecutions", - "athena:ListWorkGroups", - "athena:StartQueryExecution", - "athena:StopQueryExecution", - "athena:CancelQueryExecution", - "athena:GetCatalogs", - "athena:GetExecutionEngine", - "athena:GetExecutionEngines", - "athena:GetNamespace", - "athena:GetNamespaces", - "athena:GetTable", - "athena:GetTables", - "athena:RunQuery", - "glue:GetDatabase", - "glue:GetDatabases", - "glue:GetTable", - "glue:GetTables", - "glue:GetPartition", - "glue:GetPartitions", - "glue:BatchGetPartition", - "glue:GetCatalogImportStatus", - "glue:GetUserDefinedFunction", - "glue:GetUserDefinedFunctions" - ], - "Resource": [ - "*" - ] - } - ] + { + "Sid": "AllowListAllMyBuckets", + "Effect": "Allow", + "Action": ["s3:GetBucketLocation", "s3:ListAllMyBuckets"], + "Resource": ["*"], + }, + { + "Sid": "AllowListBucket", + "Effect": "Allow", + "Action": ["s3:ListBucket"], + "Resource": allow_list_bucket_resources, + }, + { + "Sid": "AllowGetObject", + "Effect": "Allow", + "Action": ["s3:GetObject"], + "Resource": ["arn:aws:s3:::moj-analytics-lookup-tables/*"], + }, + { + "Sid": "AllowGetPutObject", + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject"], + "Resource": ["arn:aws:s3:::aws-athena-query-results-*"], + }, + { + "Sid": "AllowGetPutDeleteObject", + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], + "Resource": allow_get_put_delete_resources, + }, + { + "Sid": "AllowReadAthenaGlue", + "Effect": "Allow", + "Action": [ + "athena:BatchGetNamedQuery", + "athena:BatchGetQueryExecution", + "athena:GetNamedQuery", + "athena:GetQueryExecution", + "athena:GetQueryResults", + "athena:GetQueryResultsStream", + "athena:GetWorkGroup", + "athena:ListNamedQueries", + "athena:ListQueryExecutions", + "athena:ListWorkGroups", + "athena:StartQueryExecution", + "athena:StopQueryExecution", + "athena:CancelQueryExecution", + "athena:GetCatalogs", + "athena:GetExecutionEngine", + "athena:GetExecutionEngines", + "athena:GetNamespace", + "athena:GetNamespaces", + "athena:GetTable", + "athena:GetTables", + "athena:GetTableMetadata", + "athena:RunQuery", + "glue:GetDatabase", + "glue:GetDatabases", + "glue:GetTable", + "glue:GetTables", + "glue:GetPartition", + "glue:GetPartitions", + "glue:BatchGetPartition", + "glue:GetCatalogImportStatus", + "glue:GetUserDefinedFunction", + "glue:GetUserDefinedFunctions", + ], + "Resource": ["*"], + }, + ] return athena_read_access def get_pass_role_to_glue_policy(iam_role: str) -> dict: policy = { - "Sid": "PassRoleToGlueService", - "Effect": "Allow", - "Action": [ - "iam:PassRole" - ], - "Resource": "arn:aws:iam::593291632749:role/{}".format(iam_role), - "Condition": { - "StringLike": { - "iam:PassedToService": [ - "glue.amazonaws.com" - ] - } - } - } + "Sid": "PassRoleToGlueService", + "Effect": "Allow", + "Action": ["iam:PassRole"], + "Resource": "arn:aws:iam::593291632749:role/{}".format(iam_role), + "Condition": {"StringLike": {"iam:PassedToService": ["glue.amazonaws.com"]}}, + } return policy def get_read_only_policy(list_of_s3_paths: list) -> dict: list_of_s3_paths = add_s3_arn_prefix(list_of_s3_paths) policy = { - "Sid": "readonly", - "Action": [ - "s3:GetObject", - "s3:GetObjectAcl", - "s3:GetObjectVersion", - ], - "Effect": "Allow", - "Resource": list_of_s3_paths, - } + "Sid": "readonly", + "Action": [ + "s3:GetObject", + "s3:GetObjectAcl", + "s3:GetObjectVersion", + ], + "Effect": "Allow", + "Resource": list_of_s3_paths, + } return policy def get_write_only_policy(list_of_s3_paths: list) -> dict: list_of_s3_paths = add_s3_arn_prefix(list_of_s3_paths) policy = { - "Sid": "writeonly", - "Action": [ - "s3:DeleteObject", - "s3:DeleteObjectVersion", - "s3:PutObject", - "s3:PutObjectAcl", - "s3:RestoreObject" - ], - "Effect": "Allow", - "Resource": list_of_s3_paths, - } + "Sid": "writeonly", + "Action": [ + "s3:DeleteObject", + "s3:DeleteObjectVersion", + "s3:PutObject", + "s3:PutObjectAcl", + "s3:RestoreObject", + ], + "Effect": "Allow", + "Resource": list_of_s3_paths, + } return policy @@ -321,11 +274,7 @@ def get_s3_list_bucket_policy(list_of_buckets: list) -> dict: list_of_buckets = add_s3_arn_prefix(list_of_buckets) policy = { "Sid": "list", - "Action": [ - "s3:ListBucket", - "s3:ListAllMyBuckets", - "s3:GetBucketLocation" - ], + "Action": ["s3:ListBucket", "s3:ListAllMyBuckets", "s3:GetBucketLocation"], "Effect": "Allow", "Resource": sorted(list(set(list_of_buckets))), } @@ -350,11 +299,9 @@ def get_secrets(iam_role: str, write=False) -> dict: "ssm:GetParametersByPath", "ssm:PutParameter", "ssm:DeleteParameter", - "ssm:DeleteParameters" + "ssm:DeleteParameters", ], - "Resource": [ - f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*" - ] + "Resource": [f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*"], } else: statement = { @@ -365,14 +312,13 @@ def get_secrets(iam_role: str, write=False) -> dict: "ssm:GetParameter", "ssm:GetParameters", "ssm:GetParameterHistory", - "ssm:GetParametersByPath" + "ssm:GetParametersByPath", ], - "Resource": [ - f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*" - ] + "Resource": [f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*"], } return statement + def get_kms_permissions(kms_arns: list) -> dict: policy = { "Sid": "kmsPermissions", @@ -381,9 +327,9 @@ def get_kms_permissions(kms_arns: list) -> dict: "kms:GenerateDataKey*", "kms:Encrypt", "kms:DescribeKey", - "kms:Decrypt" + "kms:Decrypt", ], "Effect": "Allow", "Resource": kms_arns, } - return policy \ No newline at end of file + return policy diff --git a/tests/expected_policy/all_config.json b/tests/expected_policy/all_config.json index 80b4407..b223cf3 100644 --- a/tests/expected_policy/all_config.json +++ b/tests/expected_policy/all_config.json @@ -80,6 +80,7 @@ "athena:GetNamespaces", "athena:GetTable", "athena:GetTables", + "athena:GetTableMetadata", "athena:RunQuery", "glue:GetDatabase", "glue:GetDatabases", diff --git a/tests/expected_policy/athena_full_access.json b/tests/expected_policy/athena_full_access.json index fda89f9..1dc2304 100644 --- a/tests/expected_policy/athena_full_access.json +++ b/tests/expected_policy/athena_full_access.json @@ -80,6 +80,7 @@ "athena:GetNamespaces", "athena:GetTable", "athena:GetTables", + "athena:GetTableMetadata", "athena:RunQuery", "glue:GetDatabase", "glue:GetDatabases", diff --git a/tests/expected_policy/athena_read_only.json b/tests/expected_policy/athena_read_only.json index 4073138..be206af 100644 --- a/tests/expected_policy/athena_read_only.json +++ b/tests/expected_policy/athena_read_only.json @@ -80,6 +80,7 @@ "athena:GetNamespaces", "athena:GetTable", "athena:GetTables", + "athena:GetTableMetadata", "athena:RunQuery", "glue:GetDatabase", "glue:GetDatabases", diff --git a/tests/expected_policy/athena_two_dumps.json b/tests/expected_policy/athena_two_dumps.json index 062b57c..445337b 100644 --- a/tests/expected_policy/athena_two_dumps.json +++ b/tests/expected_policy/athena_two_dumps.json @@ -82,6 +82,7 @@ "athena:GetNamespaces", "athena:GetTable", "athena:GetTables", + "athena:GetTableMetadata", "athena:RunQuery", "glue:GetDatabase", "glue:GetDatabases", From 0f628e8090835a9361087998bcfcbcba10a08e39 Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 15 May 2024 10:29:08 +0100 Subject: [PATCH 2/3] Version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 13ffd36..91cff0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "iam_builder" -version = "4.3.0" +version = "4.4.0" description = "A lil python package to generate iam policies" authors = ["Karik Isichei "] license = "MIT" From 1bfd11b7271e4900e16ff4ae296a3a2cef8d655e Mon Sep 17 00:00:00 2001 From: Mike Ratford Date: Wed, 15 May 2024 11:53:49 +0100 Subject: [PATCH 3/3] unblack --- iam_builder/templates.py | 299 +++++++++++++++++++++++---------------- 1 file changed, 177 insertions(+), 122 deletions(-) diff --git a/iam_builder/templates.py b/iam_builder/templates.py index 3dc4ed6..6c6a7df 100755 --- a/iam_builder/templates.py +++ b/iam_builder/templates.py @@ -1,7 +1,10 @@ # Formatted to match JSON IAM policy - so purposefully # not matching standard Python line break conventions -iam_base_template = {"Version": "2012-10-17", "Statement": []} +iam_base_template = { + "Version": "2012-10-17", + "Statement": [] +} # Standard segments of iam policy that don't need parameters @@ -26,9 +29,11 @@ "glue:UpdateTable", "glue:CreateUserDefinedFunction", "glue:DeleteUserDefinedFunction", - "glue:UpdateUserDefinedFunction", + "glue:UpdateUserDefinedFunction" ], - "Resource": ["*"], + "Resource": [ + "*" + ] } ], "glue_job": [ @@ -47,9 +52,11 @@ "glue:UpdateJob", "glue:ListJobs", "glue:BatchGetJobs", - "glue:GetJobBookmark", + "glue:GetJobBookmark" ], - "Resource": ["*"], + "Resource": [ + "*" + ] }, { "Sid": "CanGetLogs", @@ -59,9 +66,11 @@ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", - "logs:DescribeLogStreams", + "logs:DescribeLogStreams" ], - "Resource": ["arn:aws:logs:*:*:/aws-glue/*"], + "Resource": [ + "arn:aws:logs:*:*:/aws-glue/*" + ] }, { "Sid": "CanGetCloudWatchLogs", @@ -69,29 +78,38 @@ "Action": [ "cloudwatch:PutMetricData", "cloudwatch:GetMetricData", - "cloudwatch:ListDashboards", + "cloudwatch:ListDashboards" ], - "Resource": ["*"], + "Resource": [ + "*" + ] }, { "Sid": "CanReadGlueStuff", "Effect": "Allow", - "Action": ["s3:GetObject", "s3:PutObject"], + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], "Resource": [ "arn:aws:s3:::aws-glue-*/*", "arn:aws:s3:::*/*aws-glue-*/*", - "arn:aws:s3:::aws-glue-*", - ], - }, + "arn:aws:s3:::aws-glue-*" + ] + } ], "decrypt_statement": [ { "Sid": "allowDecrypt", "Effect": "Allow", - "Action": ["kms:Decrypt"], - "Resource": ["arn:aws:kms:::key/*"], + "Action": [ + "kms:Decrypt" + ], + "Resource": [ + "arn:aws:kms:::key/*" + ] } - ], + ] } @@ -105,128 +123,158 @@ def get_athena_read_access(dump_bucket: list) -> dict: """ # prepare segments that depend on dump bucket name allow_list_bucket_resources = ["arn:aws:s3:::moj-analytics-lookup-tables"] - allow_list_bucket_resources.extend( - ["arn:aws:s3:::" + bucket for bucket in dump_bucket] - ) + allow_list_bucket_resources.extend([ + "arn:aws:s3:::" + bucket for bucket in dump_bucket + ]) allow_get_put_delete_resources = [ "arn:aws:s3:::" + bucket + "/${aws:userid}/*" for bucket in dump_bucket ] # insert prepared sections into full iam lookup for Athena reading athena_read_access = [ - { - "Sid": "AllowListAllMyBuckets", - "Effect": "Allow", - "Action": ["s3:GetBucketLocation", "s3:ListAllMyBuckets"], - "Resource": ["*"], - }, - { - "Sid": "AllowListBucket", - "Effect": "Allow", - "Action": ["s3:ListBucket"], - "Resource": allow_list_bucket_resources, - }, - { - "Sid": "AllowGetObject", - "Effect": "Allow", - "Action": ["s3:GetObject"], - "Resource": ["arn:aws:s3:::moj-analytics-lookup-tables/*"], - }, - { - "Sid": "AllowGetPutObject", - "Effect": "Allow", - "Action": ["s3:GetObject", "s3:PutObject"], - "Resource": ["arn:aws:s3:::aws-athena-query-results-*"], - }, - { - "Sid": "AllowGetPutDeleteObject", - "Effect": "Allow", - "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], - "Resource": allow_get_put_delete_resources, - }, - { - "Sid": "AllowReadAthenaGlue", - "Effect": "Allow", - "Action": [ - "athena:BatchGetNamedQuery", - "athena:BatchGetQueryExecution", - "athena:GetNamedQuery", - "athena:GetQueryExecution", - "athena:GetQueryResults", - "athena:GetQueryResultsStream", - "athena:GetWorkGroup", - "athena:ListNamedQueries", - "athena:ListQueryExecutions", - "athena:ListWorkGroups", - "athena:StartQueryExecution", - "athena:StopQueryExecution", - "athena:CancelQueryExecution", - "athena:GetCatalogs", - "athena:GetExecutionEngine", - "athena:GetExecutionEngines", - "athena:GetNamespace", - "athena:GetNamespaces", - "athena:GetTable", - "athena:GetTables", - "athena:GetTableMetadata", - "athena:RunQuery", - "glue:GetDatabase", - "glue:GetDatabases", - "glue:GetTable", - "glue:GetTables", - "glue:GetPartition", - "glue:GetPartitions", - "glue:BatchGetPartition", - "glue:GetCatalogImportStatus", - "glue:GetUserDefinedFunction", - "glue:GetUserDefinedFunctions", - ], - "Resource": ["*"], - }, - ] + { + "Sid": "AllowListAllMyBuckets", + "Effect": "Allow", + "Action": [ + "s3:GetBucketLocation", + "s3:ListAllMyBuckets" + ], + "Resource": [ + "*" + ] + }, + { + "Sid": "AllowListBucket", + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": allow_list_bucket_resources + }, + { + "Sid": "AllowGetObject", + "Effect": "Allow", + "Action": [ + "s3:GetObject" + ], + "Resource": [ + "arn:aws:s3:::moj-analytics-lookup-tables/*" + ] + }, + { + "Sid": "AllowGetPutObject", + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], + "Resource": [ + "arn:aws:s3:::aws-athena-query-results-*" + ] + }, + { + "Sid": "AllowGetPutDeleteObject", + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:PutObject", + "s3:DeleteObject" + ], + "Resource": allow_get_put_delete_resources + }, + { + "Sid": "AllowReadAthenaGlue", + "Effect": "Allow", + "Action": [ + "athena:BatchGetNamedQuery", + "athena:BatchGetQueryExecution", + "athena:GetNamedQuery", + "athena:GetQueryExecution", + "athena:GetQueryResults", + "athena:GetQueryResultsStream", + "athena:GetWorkGroup", + "athena:ListNamedQueries", + "athena:ListQueryExecutions", + "athena:ListWorkGroups", + "athena:StartQueryExecution", + "athena:StopQueryExecution", + "athena:CancelQueryExecution", + "athena:GetCatalogs", + "athena:GetExecutionEngine", + "athena:GetExecutionEngines", + "athena:GetNamespace", + "athena:GetNamespaces", + "athena:GetTable", + "athena:GetTables", + "athena:GetTableMetadata", + "athena:RunQuery", + "glue:GetDatabase", + "glue:GetDatabases", + "glue:GetTable", + "glue:GetTables", + "glue:GetPartition", + "glue:GetPartitions", + "glue:BatchGetPartition", + "glue:GetCatalogImportStatus", + "glue:GetUserDefinedFunction", + "glue:GetUserDefinedFunctions" + ], + "Resource": [ + "*" + ] + } + ] return athena_read_access def get_pass_role_to_glue_policy(iam_role: str) -> dict: policy = { - "Sid": "PassRoleToGlueService", - "Effect": "Allow", - "Action": ["iam:PassRole"], - "Resource": "arn:aws:iam::593291632749:role/{}".format(iam_role), - "Condition": {"StringLike": {"iam:PassedToService": ["glue.amazonaws.com"]}}, - } + "Sid": "PassRoleToGlueService", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::593291632749:role/{}".format(iam_role), + "Condition": { + "StringLike": { + "iam:PassedToService": [ + "glue.amazonaws.com" + ] + } + } + } return policy def get_read_only_policy(list_of_s3_paths: list) -> dict: list_of_s3_paths = add_s3_arn_prefix(list_of_s3_paths) policy = { - "Sid": "readonly", - "Action": [ - "s3:GetObject", - "s3:GetObjectAcl", - "s3:GetObjectVersion", - ], - "Effect": "Allow", - "Resource": list_of_s3_paths, - } + "Sid": "readonly", + "Action": [ + "s3:GetObject", + "s3:GetObjectAcl", + "s3:GetObjectVersion", + ], + "Effect": "Allow", + "Resource": list_of_s3_paths, + } return policy def get_write_only_policy(list_of_s3_paths: list) -> dict: list_of_s3_paths = add_s3_arn_prefix(list_of_s3_paths) policy = { - "Sid": "writeonly", - "Action": [ - "s3:DeleteObject", - "s3:DeleteObjectVersion", - "s3:PutObject", - "s3:PutObjectAcl", - "s3:RestoreObject", - ], - "Effect": "Allow", - "Resource": list_of_s3_paths, - } + "Sid": "writeonly", + "Action": [ + "s3:DeleteObject", + "s3:DeleteObjectVersion", + "s3:PutObject", + "s3:PutObjectAcl", + "s3:RestoreObject" + ], + "Effect": "Allow", + "Resource": list_of_s3_paths, + } return policy @@ -274,7 +322,11 @@ def get_s3_list_bucket_policy(list_of_buckets: list) -> dict: list_of_buckets = add_s3_arn_prefix(list_of_buckets) policy = { "Sid": "list", - "Action": ["s3:ListBucket", "s3:ListAllMyBuckets", "s3:GetBucketLocation"], + "Action": [ + "s3:ListBucket", + "s3:ListAllMyBuckets", + "s3:GetBucketLocation" + ], "Effect": "Allow", "Resource": sorted(list(set(list_of_buckets))), } @@ -299,9 +351,11 @@ def get_secrets(iam_role: str, write=False) -> dict: "ssm:GetParametersByPath", "ssm:PutParameter", "ssm:DeleteParameter", - "ssm:DeleteParameters", + "ssm:DeleteParameters" ], - "Resource": [f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*"], + "Resource": [ + f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*" + ] } else: statement = { @@ -312,13 +366,14 @@ def get_secrets(iam_role: str, write=False) -> dict: "ssm:GetParameter", "ssm:GetParameters", "ssm:GetParameterHistory", - "ssm:GetParametersByPath", + "ssm:GetParametersByPath" ], - "Resource": [f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*"], + "Resource": [ + f"arn:aws:ssm:*:*:parameter/alpha/airflow/{iam_role}/*" + ] } return statement - def get_kms_permissions(kms_arns: list) -> dict: policy = { "Sid": "kmsPermissions", @@ -327,7 +382,7 @@ def get_kms_permissions(kms_arns: list) -> dict: "kms:GenerateDataKey*", "kms:Encrypt", "kms:DescribeKey", - "kms:Decrypt", + "kms:Decrypt" ], "Effect": "Allow", "Resource": kms_arns,