From 79229c6f6f290835061c3d9ac7a93f2f550dcfc2 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Thu, 22 May 2025 12:03:56 +0200 Subject: [PATCH 1/7] Add example IAM policies with minimum permissions to deploy and destroy Nebari on AWS --- docs/static/policies/aws/deploy.json | 283 ++++++++++++++++++++++++++ docs/static/policies/aws/destroy.json | 216 ++++++++++++++++++++ 2 files changed, 499 insertions(+) create mode 100644 docs/static/policies/aws/deploy.json create mode 100644 docs/static/policies/aws/destroy.json diff --git a/docs/static/policies/aws/deploy.json b/docs/static/policies/aws/deploy.json new file mode 100644 index 00000000..09e5d0ab --- /dev/null +++ b/docs/static/policies/aws/deploy.json @@ -0,0 +1,283 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInstanceTypes", + "ec2:DescribeInternetGateways", + "ec2:DescribeNetworkAcls", + "ec2:DescribeRegions", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:DescribeAddonVersions", + "elasticfilesystem:CreateFileSystem", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:TagOpenIDConnectProvider", + "kms:CreateKey", + "kms:DescribeKey", + "kms:ListKeys", + "resource-groups:CreateGroup", + "sts:GetCallerIdentity" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:CreateBucket", + "s3:GetAccelerateConfiguration", + "s3:GetBucketAcl", + "s3:GetBucketCORS", + "s3:GetBucketLogging", + "s3:GetBucketObjectLockConfiguration", + "s3:GetBucketPolicy", + "s3:GetBucketPublicAccessBlock", + "s3:GetBucketRequestPayment", + "s3:GetBucketTagging", + "s3:GetBucketVersioning", + "s3:GetBucketWebsite", + "s3:GetEncryptionConfiguration", + "s3:GetLifecycleConfiguration", + "s3:GetReplicationConfiguration", + "s3:ListBucket", + "s3:PutBucketPublicAccessBlock", + "s3:PutBucketTagging", + "s3:PutBucketVersioning", + "s3:PutEncryptionConfiguration" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state" + }, + { + "Effect": "Allow", + "Action": [ + "dynamodb:CreateTable", + "dynamodb:DeleteItem", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeTable", + "dynamodb:DescribeTimeToLive", + "dynamodb:GetItem", + "dynamodb:ListTagsOfResource", + "dynamodb:PutItem", + "dynamodb:TagResource" + ], + "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/PROJECT_NAME-NAMESPACE-terraform-state-lock" + }, + { + "Effect": "Allow", + "Action": [ + "kms:EnableKeyRotation", + "kms:GetKeyPolicy", + "kms:GetKeyRotationStatus", + "kms:ListResourceTags" + ], + "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/*" + }, + { + "Effect": "Allow", + "Action": [ + "ecr:CreateRepository", + "ecr:DescribeRepositories", + "ecr:ListTagsForResource", + "ecr:TagResource" + ], + "Resource": "arn:aws:ecr:REGION:ACCOUNT_ID:repository/PROJECT_NAME-NAMESPACE-jupyterlab" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateVpc", + "ec2:DescribeVpcAttribute", + "ec2:ModifyVpcAttribute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy", + "iam:CreateRole", + "iam:GetRole", + "iam:ListAttachedRolePolicies", + "iam:ListRolePolicies", + "iam:TagRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:CreatePolicy" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:policy/*" + }, + { + "Effect": "Allow", + "Action": [ + "resource-groups:GetGroup", + "resource-groups:GetGroupConfiguration", + "resource-groups:GetGroupQuery", + "resource-groups:GetTags", + "resource-groups:Tag" + ], + "Resource": "arn:aws:resource-groups:REGION:ACCOUNT_ID:group/PROJECT_NAME" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:CreateMountTarget", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeLifecycleConfiguration", + "elasticfilesystem:TagResource" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateSubnet" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateInternetGateway" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupEgress", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", + "ec2:RevokeSecurityGroupEgress" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:security-group/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AttachInternetGateway" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AssociateRouteTable", + "ec2:ModifySubnetAttribute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateRouteTable" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AssociateRouteTable", + "ec2:CreateRoute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-cluster-role" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DescribeMountTargetSecurityGroups", + "elasticfilesystem:DescribeMountTargets" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:CreateAddon", + "eks:CreateNodegroup", + "eks:DescribeCluster", + "eks:ListNodegroups", + "eks:TagResource" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:cluster/PROJECT_NAME-NAMESPACE" + }, + { + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-node-group-role" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DescribeNodegroup" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:nodegroup/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DescribeAddon" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:addon/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:CreateOpenIDConnectProvider" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:oidc-provider/*" + }, + { + "Effect": "Allow", + "Action": [ + "autoscaling:CreateOrUpdateTags" + ], + "Resource": "arn:aws:autoscaling:REGION:ACCOUNT_ID:autoScalingGroup:*:autoScalingGroupName/*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:GetObjectTagging", + "s3:GetObjectVersion", + "s3:ListMultipartUploadParts", + "s3:PutObject", + "s3:PutObjectAcl", + "s3:PutObjectTagging" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state/*" + } + ] +} diff --git a/docs/static/policies/aws/destroy.json b/docs/static/policies/aws/destroy.json new file mode 100644 index 00000000..631167c6 --- /dev/null +++ b/docs/static/policies/aws/destroy.json @@ -0,0 +1,216 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInstanceTypes", + "ec2:DescribeInternetGateways", + "ec2:DescribeNetworkAcls", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeRegions", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", + "eks:DescribeAddonVersions", + "iam:DeleteOpenIDConnectProvider", + "iam:DeletePolicy", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:ListPolicyVersions", + "kms:ListKeys", + "sts:GetCallerIdentity" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "kms:DescribeKey", + "kms:GetKeyPolicy", + "kms:GetKeyRotationStatus", + "kms:ListResourceTags", + "kms:ScheduleKeyDeletion" + ], + "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:DeleteBucket", + "s3:GetAccelerateConfiguration", + "s3:GetBucketAcl", + "s3:GetBucketCORS", + "s3:GetBucketLogging", + "s3:GetBucketObjectLockConfiguration", + "s3:GetBucketPolicy", + "s3:GetBucketPublicAccessBlock", + "s3:GetBucketRequestPayment", + "s3:GetBucketTagging", + "s3:GetBucketVersioning", + "s3:GetBucketWebsite", + "s3:GetEncryptionConfiguration", + "s3:GetLifecycleConfiguration", + "s3:GetReplicationConfiguration", + "s3:ListBucket", + "s3:ListBucketVersions", + "s3:PutBucketPublicAccessBlock", + "s3:PutEncryptionConfiguration" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state" + }, + { + "Effect": "Allow", + "Action": [ + "s3:DeleteObject", + "s3:DeleteObjectVersion", + "s3:GetObject", + "s3:GetObjectTagging", + "s3:GetObjectVersion", + "s3:ListMultipartUploadParts", + "s3:PutObject", + "s3:PutObjectAcl", + "s3:PutObjectTagging" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state/*" + }, + { + "Effect": "Allow", + "Action": [ + "dynamodb:DeleteItem", + "dynamodb:DeleteTable", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeTable", + "dynamodb:DescribeTimeToLive", + "dynamodb:GetItem", + "dynamodb:ListTagsOfResource", + "dynamodb:PutItem" + ], + "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/PROJECT_NAME-NAMESPACE-terraform-state-lock" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DeleteCluster", + "eks:DescribeCluster" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:cluster/PROJECT_NAME-NAMESPACE" + }, + { + "Effect": "Allow", + "Action": [ + "ecr:DeleteRepository", + "ecr:DescribeRepositories", + "ecr:ListTagsForResource" + ], + "Resource": "arn:aws:ecr:REGION:ACCOUNT_ID:repository/PROJECT_NAME-NAMESPACE-jupyterlab" + }, + { + "Effect": "Allow", + "Action": [ + "iam:DeleteRole", + "iam:DetachRolePolicy", + "iam:GetRole", + "iam:ListAttachedRolePolicies", + "iam:ListInstanceProfilesForRole", + "iam:ListRolePolicies" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DeleteFileSystem", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeLifecycleConfiguration" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "resource-groups:DeleteGroup", + "resource-groups:GetGroup", + "resource-groups:GetGroupConfiguration", + "resource-groups:GetGroupQuery" + ], + "Resource": "arn:aws:resource-groups:REGION:ACCOUNT_ID:group/PROJECT_NAME" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeVpcAttribute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DeleteMountTarget", + "elasticfilesystem:DescribeMountTargetSecurityGroups", + "elasticfilesystem:DescribeMountTargets" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DeleteNodegroup", + "eks:DescribeNodegroup" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:nodegroup/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DeleteAddon", + "eks:DescribeAddon" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:addon/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DisassociateRouteTable" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DeleteRouteTable" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DetachInternetGateway" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DeleteSubnet" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DeleteSecurityGroup" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:security-group/*" + } + ] +} From 90e7c6c48223ab0a04ba971d043dcf5251c263b0 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Thu, 22 May 2025 12:04:50 +0200 Subject: [PATCH 2/7] Update authentication section to mention example IAM policies with minimum permissions to deploy and destroy Nebari --- docs/docs/how-tos/nebari-aws.md | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/docs/how-tos/nebari-aws.md b/docs/docs/how-tos/nebari-aws.md index 26bd1594..2d474ffa 100644 --- a/docs/docs/how-tos/nebari-aws.md +++ b/docs/docs/how-tos/nebari-aws.md @@ -4,6 +4,12 @@ title: Deploy Nebari on AWS description: A basic overview of how to deploy Nebari on AWS --- +import CodeBlock from '@theme/CodeBlock'; +import DeployPolicy from '!!raw-loader!../../static/policies/aws/deploy.json'; +import DestroyPolicy from '!!raw-loader!../../static/policies/aws/destroy.json'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + ## Introduction This guide is to help first-time users set up an Amazon Web Services (AWS) account specifically for the purpose of using and deploying Nebari at a production scale. In this guide @@ -41,11 +47,33 @@ happens. ## Authentication In order for Nebari to make requests against the AWS API and create its infrastructure, an authentication method with the appropriate permissions will be required. The best way -to do this is using an [IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html) with suitable permissions for your AWS account and Elastic Kubernetes Service (EKS). +to do this is using an [IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html) with all the necessary permissions. + +Below are two sets of minimal IAM permissions required to deploy and destroy Nebari. You may either [create separate IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create-console.html) for each action or combine them into a single policy that includes all permissions. + +
+ AWS IAM Policies to deploy and destroy Nebari + + + {DeployPolicy} + + + {DestroyPolicy} + + +
+ +:::note + +Make sure to replace the following placeholders in the policies with your own values: +- `REGION`: The AWS region where you want to deploy Nebari (e.g., `us-west-2`) +- `ACCOUNT_ID`: Your AWS account ID (e.g., `123456789012`) +- `PROJECT_NAME`: The name of your Nebari project, specified under the `project_name` field in your `nebari-config.yaml` file (e.g., `my-nebari-project`) +- `NAMESPACE`: The namespace you want to use for your Nebari deployment, specified under the `namespace` field in your `nebari-config.yaml` file (e.g., `dev`) +::: As a [best practice](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials), do not use the AWS account `root` user for any task where it's not -required. Instead, create a new IAM user for each person that requires administrator access. Then make those users administrators by placing them into an "Administrators" user -group, to which you attach the `AdministratorAccess` managed policy. +required. Instead, create a new IAM user for each person that requires administrator access. Then make those users administrators by placing them into an "Administrators" (or any other name) user group, to which you attach the policies outlined above. If you are using an already existing IAM user, please refer to [Managing access keys for IAM users](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey) for detailed information on how to @@ -63,7 +91,7 @@ Follow these steps to set up your access keys and user accounts: ![Account setup steps for setting your first IAM user on AWS, the image contains an input for creating your username and two item boxes for selecting the type of credential needed for this account](/img/how-tos/how-tos-aws-new-iam-user.png "Creating your IAM user account") -4. Select **Attach existing policies directly**, then select `AdministratorAccess` from the list of policies. For more information, please refer to +4. Select **Attach existing policies directly**, then select the previously created policies to deploy and destroy Nebari from the list of policies. For more information, please refer to [Policies and permissions in IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html); 5. Then proceed with the new user creation setup. From 87cff5b8a62ef0d693127328198049a227e9ff92 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Thu, 22 May 2025 12:05:48 +0200 Subject: [PATCH 3/7] Add raw-loader to be able to import files and render them as code blocks in md files --- docs/yarn.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/yarn.lock b/docs/yarn.lock index d00d69ad..ff65b0ed 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -8714,6 +8714,14 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" +raw-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6" + integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + rc@1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" From cd36d3da311a58b517ccd6a94a1c0621d82521a7 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Thu, 22 May 2025 14:03:50 +0200 Subject: [PATCH 4/7] Include raw-loader in package.json --- docs/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/package.json b/docs/package.json index f287dba8..c170eba3 100644 --- a/docs/package.json +++ b/docs/package.json @@ -47,6 +47,7 @@ "docusaurus-lunr-search": "^3.3.0", "docusaurus-plugin-sass": "^0.2.5", "prism-react-renderer": "^2.1.0", + "raw-loader": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.77.8" From 0f536abcdf542f6b3b64582bcd924042e7f45b21 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Thu, 22 May 2025 14:06:00 +0200 Subject: [PATCH 5/7] Run formatter --- docs/docs/how-tos/nebari-aws.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/how-tos/nebari-aws.md b/docs/docs/how-tos/nebari-aws.md index 2d474ffa..9211f9f7 100644 --- a/docs/docs/how-tos/nebari-aws.md +++ b/docs/docs/how-tos/nebari-aws.md @@ -66,11 +66,12 @@ Below are two sets of minimal IAM permissions required to deploy and destroy Neb :::note Make sure to replace the following placeholders in the policies with your own values: + - `REGION`: The AWS region where you want to deploy Nebari (e.g., `us-west-2`) - `ACCOUNT_ID`: Your AWS account ID (e.g., `123456789012`) - `PROJECT_NAME`: The name of your Nebari project, specified under the `project_name` field in your `nebari-config.yaml` file (e.g., `my-nebari-project`) - `NAMESPACE`: The namespace you want to use for your Nebari deployment, specified under the `namespace` field in your `nebari-config.yaml` file (e.g., `dev`) -::: + ::: As a [best practice](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#lock-away-credentials), do not use the AWS account `root` user for any task where it's not required. Instead, create a new IAM user for each person that requires administrator access. Then make those users administrators by placing them into an "Administrators" (or any other name) user group, to which you attach the policies outlined above. From c7de36acc49c828ccbe8c44986ef4ed4ecd85758 Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Mon, 26 May 2025 13:52:55 +0200 Subject: [PATCH 6/7] Add missing action under the resource-groups service to the destroy policy template --- docs/static/policies/aws/destroy.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/static/policies/aws/destroy.json b/docs/static/policies/aws/destroy.json index 631167c6..ddde7900 100644 --- a/docs/static/policies/aws/destroy.json +++ b/docs/static/policies/aws/destroy.json @@ -135,7 +135,8 @@ "resource-groups:DeleteGroup", "resource-groups:GetGroup", "resource-groups:GetGroupConfiguration", - "resource-groups:GetGroupQuery" + "resource-groups:GetGroupQuery", + "resource-groups:GetTags" ], "Resource": "arn:aws:resource-groups:REGION:ACCOUNT_ID:group/PROJECT_NAME" }, From 7282ad977c10e5cd456fe284981dfa20b358e86d Mon Sep 17 00:00:00 2001 From: Marcelo Villa <36754005+marcelovilla@users.noreply.github.com> Date: Mon, 26 May 2025 14:00:05 +0200 Subject: [PATCH 7/7] Replace tabs with spaces --- docs/static/policies/aws/deploy.json | 562 +++++++++++++-------------- 1 file changed, 281 insertions(+), 281 deletions(-) diff --git a/docs/static/policies/aws/deploy.json b/docs/static/policies/aws/deploy.json index 09e5d0ab..4fdaeaaf 100644 --- a/docs/static/policies/aws/deploy.json +++ b/docs/static/policies/aws/deploy.json @@ -1,283 +1,283 @@ { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "ec2:CreateTags", - "ec2:DescribeAvailabilityZones", - "ec2:DescribeInstanceTypes", - "ec2:DescribeInternetGateways", - "ec2:DescribeNetworkAcls", - "ec2:DescribeRegions", - "ec2:DescribeRouteTables", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs", - "eks:CreateCluster", - "eks:DescribeAddonVersions", - "elasticfilesystem:CreateFileSystem", - "iam:GetOpenIDConnectProvider", - "iam:GetPolicy", - "iam:GetPolicyVersion", - "iam:TagOpenIDConnectProvider", - "kms:CreateKey", - "kms:DescribeKey", - "kms:ListKeys", - "resource-groups:CreateGroup", - "sts:GetCallerIdentity" - ], - "Resource": "*" - }, - { - "Effect": "Allow", - "Action": [ - "s3:CreateBucket", - "s3:GetAccelerateConfiguration", - "s3:GetBucketAcl", - "s3:GetBucketCORS", - "s3:GetBucketLogging", - "s3:GetBucketObjectLockConfiguration", - "s3:GetBucketPolicy", - "s3:GetBucketPublicAccessBlock", - "s3:GetBucketRequestPayment", - "s3:GetBucketTagging", - "s3:GetBucketVersioning", - "s3:GetBucketWebsite", - "s3:GetEncryptionConfiguration", - "s3:GetLifecycleConfiguration", - "s3:GetReplicationConfiguration", - "s3:ListBucket", - "s3:PutBucketPublicAccessBlock", - "s3:PutBucketTagging", - "s3:PutBucketVersioning", - "s3:PutEncryptionConfiguration" - ], - "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state" - }, - { - "Effect": "Allow", - "Action": [ - "dynamodb:CreateTable", - "dynamodb:DeleteItem", - "dynamodb:DescribeContinuousBackups", - "dynamodb:DescribeTable", - "dynamodb:DescribeTimeToLive", - "dynamodb:GetItem", - "dynamodb:ListTagsOfResource", - "dynamodb:PutItem", - "dynamodb:TagResource" - ], - "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/PROJECT_NAME-NAMESPACE-terraform-state-lock" - }, - { - "Effect": "Allow", - "Action": [ - "kms:EnableKeyRotation", - "kms:GetKeyPolicy", - "kms:GetKeyRotationStatus", - "kms:ListResourceTags" - ], - "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/*" - }, - { - "Effect": "Allow", - "Action": [ - "ecr:CreateRepository", - "ecr:DescribeRepositories", - "ecr:ListTagsForResource", - "ecr:TagResource" - ], - "Resource": "arn:aws:ecr:REGION:ACCOUNT_ID:repository/PROJECT_NAME-NAMESPACE-jupyterlab" - }, - { - "Effect": "Allow", - "Action": [ - "ec2:CreateVpc", - "ec2:DescribeVpcAttribute", - "ec2:ModifyVpcAttribute" - ], - "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" - }, - { - "Effect": "Allow", - "Action": [ - "iam:AttachRolePolicy", - "iam:CreateRole", - "iam:GetRole", - "iam:ListAttachedRolePolicies", - "iam:ListRolePolicies", - "iam:TagRole" - ], - "Resource": "arn:aws:iam::ACCOUNT_ID:role/*" - }, - { - "Effect": "Allow", - "Action": [ - "iam:CreatePolicy" - ], - "Resource": "arn:aws:iam::ACCOUNT_ID:policy/*" - }, - { - "Effect": "Allow", - "Action": [ - "resource-groups:GetGroup", - "resource-groups:GetGroupConfiguration", - "resource-groups:GetGroupQuery", - "resource-groups:GetTags", - "resource-groups:Tag" - ], - "Resource": "arn:aws:resource-groups:REGION:ACCOUNT_ID:group/PROJECT_NAME" - }, - { - "Effect": "Allow", - "Action": [ - "elasticfilesystem:CreateMountTarget", - "elasticfilesystem:DescribeFileSystems", - "elasticfilesystem:DescribeLifecycleConfiguration", - "elasticfilesystem:TagResource" - ], - "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" - }, - { - "Effect": "Allow", - "Action": [ - "ec2:CreateSubnet" - ], - "Resource": [ - "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*", - "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" - ] - }, - { - "Effect": "Allow", - "Action": [ - "ec2:CreateInternetGateway" - ], - "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*" - }, - { - "Effect": "Allow", - "Action": [ - "ec2:AuthorizeSecurityGroupEgress", - "ec2:AuthorizeSecurityGroupIngress", - "ec2:CreateSecurityGroup", - "ec2:RevokeSecurityGroupEgress" - ], - "Resource": [ - "arn:aws:ec2:REGION:ACCOUNT_ID:security-group/*", - "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" - ] - }, - { - "Effect": "Allow", - "Action": [ - "ec2:AttachInternetGateway" - ], - "Resource": [ - "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*", - "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" - ] - }, - { - "Effect": "Allow", - "Action": [ - "ec2:AssociateRouteTable", - "ec2:ModifySubnetAttribute" - ], - "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*" - }, - { - "Effect": "Allow", - "Action": [ - "ec2:CreateRouteTable" - ], - "Resource": [ - "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*", - "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" - ] - }, - { - "Effect": "Allow", - "Action": [ - "ec2:AssociateRouteTable", - "ec2:CreateRoute" - ], - "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*" - }, - { - "Effect": "Allow", - "Action": [ - "iam:PassRole" - ], - "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-cluster-role" - }, - { - "Effect": "Allow", - "Action": [ - "elasticfilesystem:DescribeMountTargetSecurityGroups", - "elasticfilesystem:DescribeMountTargets" - ], - "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" - }, - { - "Effect": "Allow", - "Action": [ - "eks:CreateAddon", - "eks:CreateNodegroup", - "eks:DescribeCluster", - "eks:ListNodegroups", - "eks:TagResource" - ], - "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:cluster/PROJECT_NAME-NAMESPACE" - }, - { - "Effect": "Allow", - "Action": [ - "iam:PassRole" - ], - "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-node-group-role" - }, - { - "Effect": "Allow", - "Action": [ - "eks:DescribeNodegroup" - ], - "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:nodegroup/PROJECT_NAME-NAMESPACE/*" - }, - { - "Effect": "Allow", - "Action": [ - "eks:DescribeAddon" - ], - "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:addon/PROJECT_NAME-NAMESPACE/*" - }, - { - "Effect": "Allow", - "Action": [ - "iam:CreateOpenIDConnectProvider" - ], - "Resource": "arn:aws:iam::ACCOUNT_ID:oidc-provider/*" - }, - { - "Effect": "Allow", - "Action": [ - "autoscaling:CreateOrUpdateTags" - ], - "Resource": "arn:aws:autoscaling:REGION:ACCOUNT_ID:autoScalingGroup:*:autoScalingGroupName/*" - }, - { - "Effect": "Allow", - "Action": [ - "s3:GetObject", - "s3:GetObjectTagging", - "s3:GetObjectVersion", - "s3:ListMultipartUploadParts", - "s3:PutObject", - "s3:PutObjectAcl", - "s3:PutObjectTagging" - ], - "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state/*" - } - ] + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInstanceTypes", + "ec2:DescribeInternetGateways", + "ec2:DescribeNetworkAcls", + "ec2:DescribeRegions", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", + "eks:CreateCluster", + "eks:DescribeAddonVersions", + "elasticfilesystem:CreateFileSystem", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:TagOpenIDConnectProvider", + "kms:CreateKey", + "kms:DescribeKey", + "kms:ListKeys", + "resource-groups:CreateGroup", + "sts:GetCallerIdentity" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:CreateBucket", + "s3:GetAccelerateConfiguration", + "s3:GetBucketAcl", + "s3:GetBucketCORS", + "s3:GetBucketLogging", + "s3:GetBucketObjectLockConfiguration", + "s3:GetBucketPolicy", + "s3:GetBucketPublicAccessBlock", + "s3:GetBucketRequestPayment", + "s3:GetBucketTagging", + "s3:GetBucketVersioning", + "s3:GetBucketWebsite", + "s3:GetEncryptionConfiguration", + "s3:GetLifecycleConfiguration", + "s3:GetReplicationConfiguration", + "s3:ListBucket", + "s3:PutBucketPublicAccessBlock", + "s3:PutBucketTagging", + "s3:PutBucketVersioning", + "s3:PutEncryptionConfiguration" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state" + }, + { + "Effect": "Allow", + "Action": [ + "dynamodb:CreateTable", + "dynamodb:DeleteItem", + "dynamodb:DescribeContinuousBackups", + "dynamodb:DescribeTable", + "dynamodb:DescribeTimeToLive", + "dynamodb:GetItem", + "dynamodb:ListTagsOfResource", + "dynamodb:PutItem", + "dynamodb:TagResource" + ], + "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/PROJECT_NAME-NAMESPACE-terraform-state-lock" + }, + { + "Effect": "Allow", + "Action": [ + "kms:EnableKeyRotation", + "kms:GetKeyPolicy", + "kms:GetKeyRotationStatus", + "kms:ListResourceTags" + ], + "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/*" + }, + { + "Effect": "Allow", + "Action": [ + "ecr:CreateRepository", + "ecr:DescribeRepositories", + "ecr:ListTagsForResource", + "ecr:TagResource" + ], + "Resource": "arn:aws:ecr:REGION:ACCOUNT_ID:repository/PROJECT_NAME-NAMESPACE-jupyterlab" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateVpc", + "ec2:DescribeVpcAttribute", + "ec2:ModifyVpcAttribute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy", + "iam:CreateRole", + "iam:GetRole", + "iam:ListAttachedRolePolicies", + "iam:ListRolePolicies", + "iam:TagRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:CreatePolicy" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:policy/*" + }, + { + "Effect": "Allow", + "Action": [ + "resource-groups:GetGroup", + "resource-groups:GetGroupConfiguration", + "resource-groups:GetGroupQuery", + "resource-groups:GetTags", + "resource-groups:Tag" + ], + "Resource": "arn:aws:resource-groups:REGION:ACCOUNT_ID:group/PROJECT_NAME" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:CreateMountTarget", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeLifecycleConfiguration", + "elasticfilesystem:TagResource" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateSubnet" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateInternetGateway" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupEgress", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateSecurityGroup", + "ec2:RevokeSecurityGroupEgress" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:security-group/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AttachInternetGateway" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:internet-gateway/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AssociateRouteTable", + "ec2:ModifySubnetAttribute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:subnet/*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateRouteTable" + ], + "Resource": [ + "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*", + "arn:aws:ec2:REGION:ACCOUNT_ID:vpc/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AssociateRouteTable", + "ec2:CreateRoute" + ], + "Resource": "arn:aws:ec2:REGION:ACCOUNT_ID:route-table/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-cluster-role" + }, + { + "Effect": "Allow", + "Action": [ + "elasticfilesystem:DescribeMountTargetSecurityGroups", + "elasticfilesystem:DescribeMountTargets" + ], + "Resource": "arn:aws:elasticfilesystem:REGION:ACCOUNT_ID:file-system/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:CreateAddon", + "eks:CreateNodegroup", + "eks:DescribeCluster", + "eks:ListNodegroups", + "eks:TagResource" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:cluster/PROJECT_NAME-NAMESPACE" + }, + { + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:role/PROJECT_NAME-NAMESPACE-eks-node-group-role" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DescribeNodegroup" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:nodegroup/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "eks:DescribeAddon" + ], + "Resource": "arn:aws:eks:REGION:ACCOUNT_ID:addon/PROJECT_NAME-NAMESPACE/*" + }, + { + "Effect": "Allow", + "Action": [ + "iam:CreateOpenIDConnectProvider" + ], + "Resource": "arn:aws:iam::ACCOUNT_ID:oidc-provider/*" + }, + { + "Effect": "Allow", + "Action": [ + "autoscaling:CreateOrUpdateTags" + ], + "Resource": "arn:aws:autoscaling:REGION:ACCOUNT_ID:autoScalingGroup:*:autoScalingGroupName/*" + }, + { + "Effect": "Allow", + "Action": [ + "s3:GetObject", + "s3:GetObjectTagging", + "s3:GetObjectVersion", + "s3:ListMultipartUploadParts", + "s3:PutObject", + "s3:PutObjectAcl", + "s3:PutObjectTagging" + ], + "Resource": "arn:aws:s3:::PROJECT_NAME-NAMESPACE-terraform-state/*" + } + ] }