diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..e10235c --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,9 @@ +{ + "features": { + "ghcr.io/devcontainers/features/python:1": { + "version": "1.6.1", + "resolved": "ghcr.io/devcontainers/features/python@sha256:d449aea663ea23ac4a7968719d5920dd57128f0429cd8e216849d5afe67651fb", + "integrity": "sha256:d449aea663ea23ac4a7968719d5920dd57128f0429cd8e216849d5afe67651fb" + } + } +} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..9fafe5f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "iam_builder", + "image": "ghcr.io/ministryofjustice/devcontainer-base:latest", + "features": { + "ghcr.io/devcontainers/features/python:1": { + "version": "3.10", + "installTools": false + } + }, + "customizations": { + "vscode": { + "extensions": [ + "EditorConfig.EditorConfig", + "GitHub.vscode-github-actions", + "GitHub.vscode-pull-request-github" + ] + } + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..64b14b5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.json] +indent_style = space +indent_size = 2 + +[*.sh] +indent_style = space +indent_size = 2 + +[{*.yml,*.yaml}] +indent_style = space +indent_size = 2 + +# This file is autogenerated +[.devcontainer/devcontainer-lock.json] +end_of_line = unset +insert_final_newline = unset diff --git a/CHANGELOG.md b/CHANGELOG.md index 16d522d..d331c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## v4.6.0 + +- Add Amazon Bedrock permissions + ## v4.5.0 - added Get/Put Object Tagging permissions for S3 readwrite access diff --git a/README.md b/README.md index 0aae703..4f1eb5c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # IAM Builder -[![Actions Status](https://github.com/moj-analytical-services/iam_builder/workflows/IAM%20Builder/badge.svg)](https://github.com/moj-analytical-services/iam_builder/actions) +[![Publish](https://github.com/moj-analytical-services/iam_builder/actions/workflows/poetry-pypi-release.yml/badge.svg)](https://github.com/moj-analytical-services/iam_builder/actions/workflows/poetry-pypi-release.yml) A python script to generate an IAM policy based on a yaml or json configuration. To install: -``` +```bash # Most stable pip install iam-builder @@ -16,7 +16,7 @@ pip install git+git://github.com/moj-analytical-services/iam_builder.git#egg=iam To use the command line interface: -``` +```bash iam_builder -c examples/iam_config.yaml -o examples/iam_policy.json ``` @@ -55,7 +55,7 @@ glue_job: true secrets: true -s3: +s3: read_only: - test_bucket_read_only/* @@ -72,6 +72,8 @@ s3: kms: - test_kms_key_arn + +bedrock: true ``` Whilst the example json (`iam_config.json`) looks like this: @@ -97,12 +99,14 @@ Whilst the example json (`iam_config.json`) looks like this: "test_bucket_read_only/write_folder/*" ] }, - "kms": ["test_kms_key_arn"] + "kms": ["test_kms_key_arn"], + "bedrock": true } ``` + - **iam_role_name:** The role name of your airflow job; required if you want to run glue jobs or access secrets. -- **athena:** Can have two keys. +- **athena:** Can have two keys. - **write**: Either `true` or `false`. If `false` then only read access to Athena (cannot create, delete or alter tables, databases and partitions). If `true` then the role will also have the ability to do stuff like CTAS queries, `DROP TABLE`, `CREATE DATABASE`, etc. - **dump_bucket**: The location in S3 (either an S3 path or a list of S3 paths) for temporarily storing the results of queries. This defaults to `mojap-athena-query-dump` and should not normally need changing. @@ -111,7 +115,7 @@ Whilst the example json (`iam_config.json`) looks like this: - **secrets:** Boolean or string; must be set to `true` or `"read"` to allow role to access secrets from AWS Parameter Store, and `readwrite` to provide read/write access. If `false` or absent role will not be able to access secrets. - **s3:** Can have up to 4 keys: `read_only`, `write_only`, `read_write`, and `deny`. Each key describes the level of access you want your iam policy to have with each s3 path. More details below: - + - **read_only:** A list of s3 paths that the iam_role should be able to access (read only). Each item in the list should either be a path to a object or finish with `/*` to denote that it can access everything within that directory. _Note the S3 paths don't start with `s3://` in the config._ - **write_only:** A list of s3 paths that the iam_role should be able to access (write only). Each item in the list should either be a path to a object or finish with `/*` to denote that it can access everything within that directory. _Note the S3 paths don't start with `s3://` in the config._ @@ -120,7 +124,7 @@ Whilst the example json (`iam_config.json`) looks like this: - **deny:** A list of s3 paths that the iam_role should _not_ be able to access. This should be used to add exceptions to wildcarded access to folders, for example excluding sensitive tables in order to provide basic access to a database. Each item in the list should either be a path to a object or finish with `/*` to denote that it can access everything within that directory. _Note the S3 paths don't start with `s3://` in the config._ -- **kms:**: A list of kms arns that the iam_role should be able to access. Can call the DescribeKey, GenerateDataKey, Decrypt, Encrypt and ReEncrypt +- **kms:** A list of kms arns that the iam_role should be able to access. Can call the DescribeKey, GenerateDataKey, Decrypt, Encrypt and ReEncrypt operations. - **bedrock:** Boolean; must be set to `true` to allow role to interact with Amazon Bedrock. If `false` or absent role will not be able to interact with Amazon Bedrock. diff --git a/examples/iam_policy.json b/examples/iam_policy.json index ee9cbfc..5409731 100644 --- a/examples/iam_policy.json +++ b/examples/iam_policy.json @@ -289,6 +289,64 @@ "arn:aws:kms:test_region:test_account:key/test_key", "arn:aws:kms:test_region_2:test_account:key/test_key_2" ] + }, + { + "Sid": "BedrockActions", + "Effect": "Allow", + "Action": [ + "bedrock:ListFoundationModels", + "bedrock:GetFoundationModel", + "bedrock:InvokeModel", + "bedrock:InvokeModelWithResponseStream", + "bedrock:CreateModelCustomizationJob", + "bedrock:GetModelCustomizationJob", + "bedrock:GetFoundationModelAvailability", + "bedrock:ListModelCustomizationJobs", + "bedrock:StopModelCustomizationJob", + "bedrock:GetCustomModel", + "bedrock:ListCustomModels", + "bedrock:DeleteCustomModel", + "bedrock:CreateProvisionedModelThroughput", + "bedrock:UpdateProvisionedModelThroughput", + "bedrock:GetProvisionedModelThroughput", + "bedrock:DeleteProvisionedModelThroughput", + "bedrock:ListProvisionedModelThroughputs", + "bedrock:ListTagsForResource", + "bedrock:UntagResource", + "bedrock:TagResource", + "bedrock:CreateAgent", + "bedrock:UpdateAgent", + "bedrock:GetAgent", + "bedrock:ListAgents", + "bedrock:CreateActionGroup", + "bedrock:UpdateActionGroup", + "bedrock:GetActionGroup", + "bedrock:ListActionGroups", + "bedrock:CreateAgentDraftSnapshot", + "bedrock:GetAgentVersion", + "bedrock:ListAgentVersions", + "bedrock:CreateAgentAlias", + "bedrock:UpdateAgentAlias", + "bedrock:GetAgentAlias", + "bedrock:ListAgentAliases", + "bedrock:InvokeAgent", + "bedrock:PutFoundationModelEntitlement", + "bedrock:GetModelInvocationLoggingConfiguration", + "bedrock:PutModelInvocationLoggingConfiguration", + "bedrock:CreateFoundationModelAgreement", + "bedrock:DeleteFoundationModelAgreement", + "bedrock:ListFoundationModelAgreementOffers", + "bedrock:GetUseCaseForModelAccess" + ], + "Resource": ["*"], + "Condition": { + "StringEquals": { + "aws:RequestedRegion": [ + "eu-central-1", + "eu-west-3" + ] + } + } } ] -} \ No newline at end of file +} diff --git a/iam_builder/templates.py b/iam_builder/templates.py index fc7a5c2..a1dc1a4 100755 --- a/iam_builder/templates.py +++ b/iam_builder/templates.py @@ -166,7 +166,7 @@ "eu-central-1", "eu-west-3" ] - } + } } } ] diff --git a/tests/expected_policy/all_config.json b/tests/expected_policy/all_config.json index faf6724..5357753 100644 --- a/tests/expected_policy/all_config.json +++ b/tests/expected_policy/all_config.json @@ -275,62 +275,62 @@ ] }, { - "Sid": "BedrockActions", - "Effect": "Allow", - "Action": [ - "bedrock:ListFoundationModels", - "bedrock:GetFoundationModel", - "bedrock:InvokeModel", - "bedrock:InvokeModelWithResponseStream", - "bedrock:CreateModelCustomizationJob", - "bedrock:GetModelCustomizationJob", - "bedrock:GetFoundationModelAvailability", - "bedrock:ListModelCustomizationJobs", - "bedrock:StopModelCustomizationJob", - "bedrock:GetCustomModel", - "bedrock:ListCustomModels", - "bedrock:DeleteCustomModel", - "bedrock:CreateProvisionedModelThroughput", - "bedrock:UpdateProvisionedModelThroughput", - "bedrock:GetProvisionedModelThroughput", - "bedrock:DeleteProvisionedModelThroughput", - "bedrock:ListProvisionedModelThroughputs", - "bedrock:ListTagsForResource", - "bedrock:UntagResource", - "bedrock:TagResource", - "bedrock:CreateAgent", - "bedrock:UpdateAgent", - "bedrock:GetAgent", - "bedrock:ListAgents", - "bedrock:CreateActionGroup", - "bedrock:UpdateActionGroup", - "bedrock:GetActionGroup", - "bedrock:ListActionGroups", - "bedrock:CreateAgentDraftSnapshot", - "bedrock:GetAgentVersion", - "bedrock:ListAgentVersions", - "bedrock:CreateAgentAlias", - "bedrock:UpdateAgentAlias", - "bedrock:GetAgentAlias", - "bedrock:ListAgentAliases", - "bedrock:InvokeAgent", - "bedrock:PutFoundationModelEntitlement", - "bedrock:GetModelInvocationLoggingConfiguration", - "bedrock:PutModelInvocationLoggingConfiguration", - "bedrock:CreateFoundationModelAgreement", - "bedrock:DeleteFoundationModelAgreement", - "bedrock:ListFoundationModelAgreementOffers", - "bedrock:GetUseCaseForModelAccess" - ], - "Resource": ["*"], - "Condition": { - "StringEquals": { - "aws:RequestedRegion": [ - "eu-central-1", - "eu-west-3" - ] - } - } - } + "Sid": "BedrockActions", + "Effect": "Allow", + "Action": [ + "bedrock:ListFoundationModels", + "bedrock:GetFoundationModel", + "bedrock:InvokeModel", + "bedrock:InvokeModelWithResponseStream", + "bedrock:CreateModelCustomizationJob", + "bedrock:GetModelCustomizationJob", + "bedrock:GetFoundationModelAvailability", + "bedrock:ListModelCustomizationJobs", + "bedrock:StopModelCustomizationJob", + "bedrock:GetCustomModel", + "bedrock:ListCustomModels", + "bedrock:DeleteCustomModel", + "bedrock:CreateProvisionedModelThroughput", + "bedrock:UpdateProvisionedModelThroughput", + "bedrock:GetProvisionedModelThroughput", + "bedrock:DeleteProvisionedModelThroughput", + "bedrock:ListProvisionedModelThroughputs", + "bedrock:ListTagsForResource", + "bedrock:UntagResource", + "bedrock:TagResource", + "bedrock:CreateAgent", + "bedrock:UpdateAgent", + "bedrock:GetAgent", + "bedrock:ListAgents", + "bedrock:CreateActionGroup", + "bedrock:UpdateActionGroup", + "bedrock:GetActionGroup", + "bedrock:ListActionGroups", + "bedrock:CreateAgentDraftSnapshot", + "bedrock:GetAgentVersion", + "bedrock:ListAgentVersions", + "bedrock:CreateAgentAlias", + "bedrock:UpdateAgentAlias", + "bedrock:GetAgentAlias", + "bedrock:ListAgentAliases", + "bedrock:InvokeAgent", + "bedrock:PutFoundationModelEntitlement", + "bedrock:GetModelInvocationLoggingConfiguration", + "bedrock:PutModelInvocationLoggingConfiguration", + "bedrock:CreateFoundationModelAgreement", + "bedrock:DeleteFoundationModelAgreement", + "bedrock:ListFoundationModelAgreementOffers", + "bedrock:GetUseCaseForModelAccess" + ], + "Resource": ["*"], + "Condition": { + "StringEquals": { + "aws:RequestedRegion": [ + "eu-central-1", + "eu-west-3" + ] + } + } + } ] -} \ No newline at end of file +}