From c79892373c580a23f878c01cbd2c5002ec6bf3b3 Mon Sep 17 00:00:00 2001 From: iuri aranda Date: Fri, 3 Jan 2025 17:08:09 +0100 Subject: [PATCH] Implement the admin role in terraform Also update the docs --- CHANGELOG.md | 2 +- README.md | 42 ++++++--- admin-role/admin-role.tf | 99 +++++++++++++++++++- admin-role/cloud-formation-template.yaml | 99 -------------------- capa-controller-role/giantswarm-capa-role.tf | 3 +- capa-controller-role/variables.tf | 12 --- 6 files changed, 124 insertions(+), 133 deletions(-) delete mode 100644 admin-role/cloud-formation-template.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 00858f9..a7f1bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Reduce setup options to only CloudFormation stacks +- Reduce setup options to only OpenTofu / Terraform ## [4.3.1] - 2024-12-18 diff --git a/README.md b/README.md index 5a773f5..1d6ff78 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,46 @@ # giantswarm-aws-account-prerequisites -This repo contains Cloud Formation templates to prepare AWS accounts for running Giant Swarm clusters based on Cluster API Provider for AWS (CAPA). +This repo contains OpenTofu / Terraform configuration to prepare AWS accounts for running Giant Swarm clusters based on Cluster API Provider for AWS (CAPA). ## Before starting Make sure to adjust AWS account limits according to [these docs](https://docs.giantswarm.io/getting-started/prepare-your-provider-infrastructure/aws/#quotas). Then please create the admin role for Giant Swarm staff access, as shown below. -## 1. admin-role +## admin-role In all AWS accounts where you plan to run a management cluster and workload clusters, Giant Swarm staff need to have access in order to manage, operate and troubleshoot the infrastructure. -Therefore, please create the admin CloudFormation stack in each of those accounts. That can be done either from our [admin role stack template (direct link to AWS Console dialog)](https://eu-central-1.console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/quickcreate?templateURL=https://cf-templates-giantswarm.s3.eu-central-1.amazonaws.com/admin-role/cloud-formation-template.yaml&stackName=GiantSwarmAdminRoleBootstrap&¶m_AdminRoleName=GiantSwarmAdmin), or by uploading the [admin role stack definition file](./admin-role/cloud-formation-template.yaml) when creating a new stack in the AWS console. +Therefore, please run OpenTofu or Terraform using the configuration provided in the `admin-role` directory, using AWS credentials for the account where the role needs to be created. -Review the changes and click `Create stack`. In case of any error, please check the `Events` tab in the CloudFormation console and report the error to the Giant Swarm staff. +```console +export AWS_PROFILE=example +tofu init +tofu apply # review the proposed changes before approving +``` -## 2. capa-controller-role +**Once the admin role is created, Giant Swarm staff will take over the maintenance of it and the CAPA controller roles for all the MCs that operate under that account, so there is no further action needed by customers.** -In the AWS account where you plan to run the management cluster, you need to create a role that the Cluster API Provider AWS (CAPA) controller will assume to create and manage workload clusters and all infrastructure resources. +## capa-controller-role -The same applies to all accounts where CAPA should be able to create workload clusters, since they don't necessarily need to run in the same account as your management cluster. The `AWSClusterRoleIdentity` objects on the management cluster define in which accounts you want to create workload clusters. +The Cluster API Provider AWS (CAPA) controller requires an IAM role to assume in order to create and manage clusters and all infrastructure resources in a specific AWS account. As mentioned above, the lifecycle of this role is normally managed by Giant Swarm once the admin role is provisioned. -**Once the admin role is created (see above), Giant Swarm staff takes over creating and maintaining the CloudFormation stack for each of your desired accounts and there is no further action needed by customers. Only if for some reason, you want to manage them yourself**, you can use these instructions: +But in case that for some reason the CAPA controller role needs to be managed individually by the customer, the OpenTofu / Terraform configuration in the `capa-controller-role` directory can be used, using AWS credentials for the account where the role needs to be created. -- Creation: Log into the right account in AWS Console, choose your desired region and create the CloudFormation stack from our [capa-controller-role stack template (direct link to AWS Console dialog)](https://eu-central-1.console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/quickcreate?templateURL=https://cf-templates-giantswarm.s3.eu-central-1.amazonaws.com/capa-controller-role/cloud-formation-template.yaml&stackName=CAPAControllerRoleBootstrap¶m_InstallationName=CHANGE_THIS_FOR_THE_INSTALLATION_NAME¶m_ManagementClusterOidcProviderDomain=MANAGEMENT_CLUSTER_OIDC_PROVIDER_DOMAIN). Alternatively, you can upload the [capa-controller-role stack definition file](./capa-controller-role/cloud-formation-template.yaml) in this repository. +### Adjust variables - You will be asked for the following parameters: +Note that for this stack there are some additional variables that you need to provide: - - `InstallationName`: the name of the installation which you have agreed with Giant Swarm upfront. - - `ByoVpc` (optional - defaults to `false`): if `true`, the CAPA role will be created without the permissions needed to manage VPCs. Turn this on if you only want to create clusters in VPCs that you have already created, without requiring CAPA to create or manage VPCs and its networking resources (like NAT/internet gateways, subnets, etc.). - - `ManagementClusterOidcProviderDomain`: the domain name used by the MC OIDC provider. Normally `irsa.`. +- `installation_name`: the name of the installation which you have agreed with Giant Swarm upfront. +- `management_cluster_oidc_provider_domain`: the domain name used by the MC OIDC provider. Normally `irsa.`. +- `byovpc` (optional - defaults to `false`): if `true`, the CAPA role will be created without the permissions needed to manage VPCs - Review the changes and click `Create stack`. In case of any error, please check the `Events` tab in the CloudFormation console and report the error to the Giant Swarm staff. -- Update: Select the CloudFormation stack in AWS Console, then `Update > Replace existing template` and use the latest released definition `https://cf-templates-giantswarm.s3.eu-central-1.amazonaws.com/capa-controller-role/cloud-formation-template.yaml` as source (or the [stack definition file](./capa-controller-role/cloud-formation-template.yaml) in this repository). +### Execution + +```console +export AWS_PROFILE=example +export TF_VAR_installation_name=foo +export TF_VAR_management_cluster_oidc_provider_domain=irsa.foo.bar.com +export TF_VAR_byovpc=false +tofu init +tofu apply # review the proposed changes before approving +``` diff --git a/admin-role/admin-role.tf b/admin-role/admin-role.tf index d5578c4..20962d9 100644 --- a/admin-role/admin-role.tf +++ b/admin-role/admin-role.tf @@ -9,11 +9,100 @@ variable "gs_user_account" { } } -resource "aws_cloudformation_stack" "giantswarm_admin" { - name = "GiantSwarmAdminRoleBootstrap" - template_body = file("${path.module}/cloud-formation-template.yaml") +data "aws_partition" "current" {} - parameters = { - GiantSwarmUserAccount = var.gs_user_account +data "aws_iam_policy_document" "giantswarm_admin" { + statement { + effect = "Allow" + resources = ["*"] + + actions = [ + "acm:*", + "autoscaling:*", + "cloudformation:*", + "cloudfront:*", + "cloudwatch:*", + "dynamodb:*", + "ec2:*", + "ecr:*", + "elasticfilesystem:*", + "elasticloadbalancing:*", + "events:*", + "ram:*", + "iam:AddRoleToInstanceProfile", + "iam:AttachRolePolicy", + "iam:CreateAccessKey", + "iam:CreateInstanceProfile", + "iam:CreatePolicy", + "iam:CreatePolicyVersion", + "iam:CreateRole", + "iam:CreateServiceLinkedRole", + "iam:DeleteAccessKey", + "iam:DeleteInstanceProfile", + "iam:DeletePolicy", + "iam:DeletePolicyVersion", + "iam:DeleteRole", + "iam:DeleteRolePolicy", + "iam:DeleteServiceLinkedRole", + "iam:DetachRolePolicy", + "iam:GenerateServiceLastAccessedDetails", + "iam:Get*", + "iam:List*", + "iam:PassRole", + "iam:PutRolePolicy", + "iam:RemoveRoleFromInstanceProfile", + "iam:TagPolicy", + "iam:TagRole", + "iam:UpdateAccessKey", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateRoleDescription", + "kms:*", + "logs:*", + "route53:*", + "route53domains:*", + "route53resolver:*", + "s3:*", + "sts:AssumeRole", + "sts:DecodeAuthorizationMessage", + "sts:GetFederationToken", + "support:*", + "trustedadvisor:*", + "sqs:*", + "iam:CreateOpenIDConnectProvider", + "iam:DeleteOpenIDConnectProvider", + "iam:TagOpenIDConnectProvider", + "iam:UntagOpenIDConnectProvider", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:RemoveClientIDFromOpenIDConnectProvider", + "iam:AddClientIDToOpenIDConnectProvider" + ] + } +} + +data "aws_iam_policy_document" "giantswarm_admin_assume" { + statement { + effect = "Allow" + + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${var.gs_user_account}:root"] + } + + actions = ["sts:AssumeRole"] } } + +resource "aws_iam_role" "giantswarm_admin" { + name = "GiantSwarmAdmin" + assume_role_policy = data.aws_iam_policy_document.giantswarm_admin_assume.json +} + +resource "aws_iam_policy" "giantswarm_admin_policy" { + name = "GiantSwarmAdmin" + policy = data.aws_iam_policy_document.giantswarm_admin.json +} + +resource "aws_iam_role_policy_attachment" "giantswarm_policy_attachment" { + role = aws_iam_role.giantswarm_admin.name + policy_arn = aws_iam_policy.giantswarm_admin_policy.arn +} diff --git a/admin-role/cloud-formation-template.yaml b/admin-role/cloud-formation-template.yaml deleted file mode 100644 index ea50172..0000000 --- a/admin-role/cloud-formation-template.yaml +++ /dev/null @@ -1,99 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Description: CloudFormation template for bootstrapping the admin role in your AWS account. - -Parameters: - GiantSwarmUserAccount: - Type: String - Description: "Account of Giant Swarm IAM users (`084190472784`, except for China). Assumed to be in the same partition as the CloudFormation stack account (`aws`, or `aws-cn` for China)." - Default: "084190472784" - # No `AllowedValues` here, since we don't publish the identifiers of other accounts - AllowedPattern: "^[0-9]{12}$" - -Resources: - GiantSwarmAdminRole: - Type: "AWS::IAM::Role" - Properties: - RoleName: GiantSwarmAdmin - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: "Allow" - Principal: - AWS: !Sub "arn:${AWS::Partition}:iam::${GiantSwarmUserAccount}:root" - Action: "sts:AssumeRole" - - GiantSwarmAdminPolicy: - Type: "AWS::IAM::Policy" - Properties: - PolicyName: "GiantSwarmAdmin" - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: "Allow" - Action: - - "acm:*" - - "autoscaling:*" - - "cloudformation:*" - - "cloudfront:*" - - "cloudwatch:*" - - "dynamodb:*" - - "ec2:*" - - "ecr:*" - - "elasticfilesystem:*" - - "elasticloadbalancing:*" - - "events:*" - - "ram:*" - - "iam:AddRoleToInstanceProfile" - - "iam:AttachRolePolicy" - - "iam:CreateAccessKey" - - "iam:CreateInstanceProfile" - - "iam:CreatePolicy" - - "iam:CreatePolicyVersion" - - "iam:CreateRole" - - "iam:CreateServiceLinkedRole" - - "iam:DeleteAccessKey" - - "iam:DeleteInstanceProfile" - - "iam:DeletePolicy" - - "iam:DeletePolicyVersion" - - "iam:DeleteRole" - - "iam:DeleteRolePolicy" - - "iam:DeleteServiceLinkedRole" - - "iam:DetachRolePolicy" - - "iam:GenerateServiceLastAccessedDetails" - - "iam:Get*" - - "iam:List*" - - "iam:PassRole" - - "iam:PutRolePolicy" - - "iam:RemoveRoleFromInstanceProfile" - - "iam:TagPolicy" - - "iam:TagRole" - - "iam:UpdateAccessKey" - - "iam:UpdateAssumeRolePolicy" - - "iam:UpdateRoleDescription" - - "kms:*" - - "logs:*" - - "route53:*" - - "route53domains:*" - - "route53resolver:*" - - "s3:*" - - "sts:AssumeRole" - - "sts:DecodeAuthorizationMessage" - - "sts:GetFederationToken" - - "support:*" - - "trustedadvisor:*" - - "sqs:*" - - "iam:CreateOpenIDConnectProvider" - - "iam:DeleteOpenIDConnectProvider" - - "iam:TagOpenIDConnectProvider" - - "iam:UntagOpenIDConnectProvider" - - "iam:UpdateOpenIDConnectProviderThumbprint" - - "iam:RemoveClientIDFromOpenIDConnectProvider" - - "iam:AddClientIDToOpenIDConnectProvider" - Resource: "*" - Roles: - - !Ref GiantSwarmAdminRole - -Outputs: - GiantSwarmAdminRoleArn: - Description: "The ARN of the IAM role" - Value: !GetAtt GiantSwarmAdminRole.Arn diff --git a/capa-controller-role/giantswarm-capa-role.tf b/capa-controller-role/giantswarm-capa-role.tf index 0bc91d5..bae980a 100644 --- a/capa-controller-role/giantswarm-capa-role.tf +++ b/capa-controller-role/giantswarm-capa-role.tf @@ -14,6 +14,7 @@ terraform { } data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} resource "aws_iam_role" "giantswarm_capa_controller_role" { name = "giantswarm-${var.installation_name}-capa-controller" @@ -21,7 +22,7 @@ resource "aws_iam_role" "giantswarm_capa_controller_role" { INSTALLATION_NAME = var.installation_name AWS_ACCOUNT_ID = data.aws_caller_identity.current.account_id MANAGEMENT_CLUSTER_OIDC_PROVIDER_DOMAIN = var.management_cluster_oidc_provider_domain - AWS_PARTITION = var.aws_partition + AWS_PARTITION = data.aws_partition.current.partition GS_USER_ACCOUNT = var.gs_user_account }) tags = local.tags diff --git a/capa-controller-role/variables.tf b/capa-controller-role/variables.tf index d6f2a2d..4708584 100644 --- a/capa-controller-role/variables.tf +++ b/capa-controller-role/variables.tf @@ -30,18 +30,6 @@ variable "byovpc" { default = false } -variable "aws_partition" { - type = string - description = "AWS partition (e.g. `aws` or `aws-cn`)" - default = "aws" -} - -variable "import_existing" { - type = bool - description = "If true, the existing role and policies will be imported instead of created" - default = false -} - variable "additional_policies" { type = map(string) description = "Map of additional policy documents to attach to the IAM role"