From dda4119f3f3b2c630a954036b3ab6e6c69be2d44 Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Wed, 27 Mar 2024 13:33:33 +0200 Subject: [PATCH 1/6] Cloudformation yml to create elast-agent user and generate direct access key --- ...nt-direct-access-key-cspm-organization.yml | 175 ++++++++++++++++++ .../elastic-agent-direct-access-key-cspm.yml | 32 ++++ scripts/publish_cft.sh | 2 + 3 files changed, 209 insertions(+) create mode 100644 deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml create mode 100644 deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml new file mode 100644 index 0000000000..33c0077ab5 --- /dev/null +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml @@ -0,0 +1,175 @@ +AWSTemplateFormatVersion: "2010-09-09" + +Description: Creates elastic-agent cspm user, role, and access key, and outputs the access key + +Parameters: + OrganizationalUnitIds: + Description: | + Comma-separated list of organizational units to deploy the IAM roles to. + Specify the unique IDs of the organizational units where the roles should be deployed. + Example: ou-abc123,ou-def456,ou-ghi789 + Type: CommaDelimitedList + AllowedPattern: ^(ou-[0-9a-z]{4,32}-[a-z0-9]{8,32}|r-[0-9a-z]{4,32})$ + + ScanManagementAccount: + Description: | + When set to "Yes", the Management Account resources will be scanned, + regardless of selected Organizational Unit IDs. Likewise, when set to + "No", the Management Account resources will not be scanned, even if + the Management Account belongs to a selected Organizational Unit. + Type: String + AllowedValues: + - "Yes" + - "No" + Default: "Yes" + ConstraintDescription: Must specify "Yes" or "No" + +Conditions: + ScanManagementAccountEnabled: !Equals + - !Ref ScanManagementAccount + - "Yes" + +Resources: + ElasticCSPMUser: + Type: "AWS::IAM::User" + Properties: + UserName: !Join + - '-' + - - "elasticagent-user-cspm" + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId + + CloudbeatRootRole: + Type: AWS::IAM::Role + Properties: + RoleName: cloudbeat-root + Description: Role that cloudbeat uses to assume roles in other accounts + Tags: + - Key: cloudbeat_scan_management_account + Value: !Ref ScanManagementAccount + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + AWS: !Ref AWS::AccountId + Action: + - sts:AssumeRole + - Effect: Allow + Principal: + AWS: !GetAtt ElasticCSPMUser.Arn + Action: + - sts:AssumeRole + - Effect: Allow + Principal: + Service: + - ec2.amazonaws.com + Action: + - sts:AssumeRole + Path: / + Policies: + - PolicyName: cloudbeat-root-permissions + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - iam:GetRole + - iam:ListAccountAliases + - iam:ListGroup + - iam:ListRoles + - iam:ListUsers + Resource: '*' + - Effect: Allow + Action: + - organizations:List* + - organizations:Describe* + Resource: '*' + - Effect: Allow + Action: + - sts:AssumeRole + Resource: '*' + + CloudbeatRoleStackSet: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: cloudbeat-role-stackset + Description: StackSet for deploying the cloudbeat-securityaudit IAM role to member accounts in the specified organizational units. + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: false + Capabilities: + - CAPABILITY_NAMED_IAM + ManagedExecution: + Active: true + Parameters: + - ParameterKey: RootRoleArn + ParameterValue: !GetAtt CloudbeatRootRole.Arn + PermissionModel: SERVICE_MANAGED + StackInstancesGroup: + - DeploymentTargets: + OrganizationalUnitIds: !Ref OrganizationalUnitIds + Regions: + - !Ref AWS::Region + TemplateBody: | + AWSTemplateFormatVersion: '2010-09-09' + Description: Creates IAM roles needed for multi-account access + Parameters: + RootRoleArn: + Type: String + Resources: + CloudbeatMemberRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: cloudbeat-securityaudit + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: !Ref RootRoleArn + Action: + - sts:AssumeRole + Path: / + ManagedPolicyArns: + - arn:aws:iam::aws:policy/SecurityAudit + + CloudbeatManagementAccountAuditRole: + Type: AWS::IAM::Role + Properties: + RoleName: cloudbeat-securityaudit + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + AWS: !GetAtt CloudbeatRootRole.Arn + Action: + - sts:AssumeRole + Path: / + ManagedPolicyArns: + - arn:aws:iam::aws:policy/SecurityAudit + Condition: ScanManagementAccountEnabled + + ElasticCSPMAccessKey: + Type: "AWS::IAM::AccessKey" + Properties: + UserName: !Ref ElasticCSPMUser + + +Outputs: + AccessKeyId: + Description: "Access Key ID" + Value: !Ref ElasticCSPMAccessKey + Export: + Name: "AccessKeyId" + + SecretAccessKey: + Description: "Secret Access Key" + Value: !GetAtt ElasticCSPMAccessKey.SecretAccessKey + Export: + Name: "SecretAccessKey" + diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml new file mode 100644 index 0000000000..4924559d5a --- /dev/null +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml @@ -0,0 +1,32 @@ +AWSTemplateFormatVersion: "2010-09-09" + +Description: Creates elastic-agent cspm user, role, and access key, and outputs the access key + +Parameters: {} + +Resources: + ElasticCSPMUser: + Type: "AWS::IAM::User" + Properties: + UserName: "elasticagent-cspm" + ManagedPolicyArns: + - 'arn:aws:iam::aws:policy/SecurityAudit' + + ElasticCSPMAccessKey: + Type: "AWS::IAM::AccessKey" + Properties: + UserName: !Ref ElasticCSPMUser + +Outputs: + AccessKeyId: + Description: "Access Key ID" + Value: !Ref ElasticCSPMAccessKey + Export: + Name: "AccessKeyId" + + SecretAccessKey: + Description: "Secret Access Key" + Value: !GetAtt ElasticCSPMAccessKey.SecretAccessKey + Export: + Name: "SecretAccessKey" + diff --git a/scripts/publish_cft.sh b/scripts/publish_cft.sh index d4a8b28887..9e13038f9a 100755 --- a/scripts/publish_cft.sh +++ b/scripts/publish_cft.sh @@ -18,3 +18,5 @@ version=$(grep defaultBeatVersion version/version.go | cut -f2 -d "\"") upload_file deploy/cloudformation/elastic-agent-ec2-cnvm.yml "cloudformation-cnvm" "$version" upload_file deploy/cloudformation/elastic-agent-ec2-cspm.yml "cloudformation-cspm-single-account" "$version" upload_file deploy/cloudformation/elastic-agent-ec2-cspm-organization.yml "cloudformation-cspm-organization-account" "$version" +upload_file deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml "cloudformation-cspm-direct-access-key-single-account.yml" "$version" +upload_file deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml "cloudformation-cspm-direct-access-key-organization-account.yml" "$version" From 40d7009dce5312b00254ca2edef8760268b94e4c Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Mon, 8 Apr 2024 09:52:02 +0300 Subject: [PATCH 2/6] cloudformation ga --- .github/workflows/cloudformation-ci.yml | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/.github/workflows/cloudformation-ci.yml b/.github/workflows/cloudformation-ci.yml index d68d5f887f..d602a5a78e 100644 --- a/.github/workflows/cloudformation-ci.yml +++ b/.github/workflows/cloudformation-ci.yml @@ -115,3 +115,42 @@ jobs: terraform destroy --auto-approve -target="module.ec_deployment" -target="module.ec_project" aws cloudformation delete-stack --stack-name ${{ env.CNVM_STACK_NAME }} aws cloudformation wait stack-delete-complete --stack-name ${{ env.CNVM_STACK_NAME }} + + + Deploy-CloudFormation-DirectKeys: + name: "Deploy CloudFormation DirectKeys" + runs-on: ubuntu-latest + timeout-minutes: 40 + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Init Hermit + run: ./bin/hermit env -r >> $GITHUB_ENV + working-directory: ./ + + - name: Set up unique deployment names + run: | + suffix="$(date +%s | tail -c 3)" + echo "DIRECT_KEY_STACK_NAME=direct-key-stack-pr${{ github.event.number }}-$suffix" >> $GITHUB_ENV + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: "eu-west-1" + + - name: Deploy CloudFormation stack + env: + CF_FILE: 'deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml' + run: | + aws cloudformation validate-template --template-body file://${{ env.CF_FILE }} + aws cloudformation create-stack --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} --template-body file://${{ env.CF_FILE }} --capabilities CAPABILITY_NAMED_IAM + aws cloudformation wait stack-create-complete --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} + + - name: Cleanup Environment + if: always() + run: | + aws cloudformation delete-stack --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} + aws cloudformation wait stack-delete-complete --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} From 50c8bc680767c76a9248a236a5a2492e20411dc1 Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Mon, 8 Apr 2024 10:16:05 +0300 Subject: [PATCH 3/6] unique username --- ...astic-agent-direct-access-key-cspm-organization.yml | 2 +- .../elastic-agent-direct-access-key-cspm.yml | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml index 33c0077ab5..b0a4fcf308 100644 --- a/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml @@ -35,7 +35,7 @@ Resources: Properties: UserName: !Join - '-' - - - "elasticagent-user-cspm" + - - 'elasticagent-user-cspm' - !Select - 2 - !Split diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml index 4924559d5a..52800a61d2 100644 --- a/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml @@ -1,5 +1,4 @@ AWSTemplateFormatVersion: "2010-09-09" - Description: Creates elastic-agent cspm user, role, and access key, and outputs the access key Parameters: {} @@ -8,7 +7,14 @@ Resources: ElasticCSPMUser: Type: "AWS::IAM::User" Properties: - UserName: "elasticagent-cspm" + UserName: !Join + - '-' + - - 'elasticagent-user-cspm' + - !Select + - 2 + - !Split + - / + - !Ref AWS::StackId ManagedPolicyArns: - 'arn:aws:iam::aws:policy/SecurityAudit' From 527cdc96550d9c3360c4db9ad465e6e9c6e9a29d Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Mon, 8 Apr 2024 10:33:33 +0300 Subject: [PATCH 4/6] add aws ci with new credentials --- .github/workflows/cloudformation-ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/cloudformation-ci.yml b/.github/workflows/cloudformation-ci.yml index d602a5a78e..f07ae1a286 100644 --- a/.github/workflows/cloudformation-ci.yml +++ b/.github/workflows/cloudformation-ci.yml @@ -149,6 +149,23 @@ jobs: aws cloudformation create-stack --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} --template-body file://${{ env.CF_FILE }} --capabilities CAPABILITY_NAMED_IAM aws cloudformation wait stack-create-complete --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} + - name: Get Direct Keys + shell: bash + run: | + BODY="$(aws cloudformation describe-stacks --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} --query 'Stacks[0].Outputs' --output json)" + NEW_ACCESS_KEY_ID="$(echo "${BODY}" | jq '.[] | select(.OutputKey | test("AccessKeyId")) | .OutputValue')" + NEW_SECRET_ACCESS_KEY="$(echo "${BODY}" | jq '.[] | select(.OutputKey | test("SecretAccessKey")) | .OutputValue')" + echo "NEW_ACCESS_KEY_ID=${NEW_ACCESS_KEY_ID}" >> $GITHUB_ENV + echo "NEW_SECRET_ACCESS_KEY=${NEW_SECRET_ACCESS_KEY}" >> $GITHUB_ENV + + - name: Run AWS integration tests + uses: ./.github/actions/aws-ci + with: + elk-version: ${{ env.ELK_VERSION }} + aws-access-key-id: ${{ env.NEW_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ env.NEW_SECRET_ACCESS_KEY }} + aws-account-type: single-account + - name: Cleanup Environment if: always() run: | From e6c1ba496e5674bed20371185cb2089b642ba5c4 Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Tue, 9 Apr 2024 10:35:21 +0300 Subject: [PATCH 5/6] fix ci --- .github/workflows/cloudformation-ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cloudformation-ci.yml b/.github/workflows/cloudformation-ci.yml index f07ae1a286..893f607886 100644 --- a/.github/workflows/cloudformation-ci.yml +++ b/.github/workflows/cloudformation-ci.yml @@ -125,9 +125,10 @@ jobs: - name: Check out the repo uses: actions/checkout@v4 - - name: Init Hermit - run: ./bin/hermit env -r >> $GITHUB_ENV - working-directory: ./ + - name: Hermit Environment + uses: ./.github/actions/hermit + with: + init-tools: 'true' - name: Set up unique deployment names run: | @@ -153,8 +154,8 @@ jobs: shell: bash run: | BODY="$(aws cloudformation describe-stacks --stack-name ${{ env.DIRECT_KEY_STACK_NAME }} --query 'Stacks[0].Outputs' --output json)" - NEW_ACCESS_KEY_ID="$(echo "${BODY}" | jq '.[] | select(.OutputKey | test("AccessKeyId")) | .OutputValue')" - NEW_SECRET_ACCESS_KEY="$(echo "${BODY}" | jq '.[] | select(.OutputKey | test("SecretAccessKey")) | .OutputValue')" + NEW_ACCESS_KEY_ID="$(echo "${BODY}" | jq -r '.[] | select(.OutputKey | test("AccessKeyId")) | .OutputValue')" + NEW_SECRET_ACCESS_KEY="$(echo "${BODY}" | jq -r '.[] | select(.OutputKey | test("SecretAccessKey")) | .OutputValue')" echo "NEW_ACCESS_KEY_ID=${NEW_ACCESS_KEY_ID}" >> $GITHUB_ENV echo "NEW_SECRET_ACCESS_KEY=${NEW_SECRET_ACCESS_KEY}" >> $GITHUB_ENV From 37b8fbebc9297a7af601fa1439462b05ac609044 Mon Sep 17 00:00:00 2001 From: Kostas Stamatakis Date: Tue, 9 Apr 2024 16:52:46 +0300 Subject: [PATCH 6/6] fmt --- ...ent-direct-access-key-cspm-organization.yml | 16 +++++++--------- .../elastic-agent-direct-access-key-cspm.yml | 18 +++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml index b0a4fcf308..817afa518e 100644 --- a/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm-organization.yml @@ -31,11 +31,11 @@ Conditions: Resources: ElasticCSPMUser: - Type: "AWS::IAM::User" + Type: AWS::IAM::User Properties: UserName: !Join - '-' - - - 'elasticagent-user-cspm' + - - elasticagent-user-cspm - !Select - 2 - !Split @@ -155,21 +155,19 @@ Resources: Condition: ScanManagementAccountEnabled ElasticCSPMAccessKey: - Type: "AWS::IAM::AccessKey" + Type: AWS::IAM::AccessKey Properties: UserName: !Ref ElasticCSPMUser - Outputs: AccessKeyId: - Description: "Access Key ID" + Description: Access Key ID Value: !Ref ElasticCSPMAccessKey Export: - Name: "AccessKeyId" + Name: AccessKeyId SecretAccessKey: - Description: "Secret Access Key" + Description: Secret Access Key Value: !GetAtt ElasticCSPMAccessKey.SecretAccessKey Export: - Name: "SecretAccessKey" - + Name: SecretAccessKey diff --git a/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml index 52800a61d2..f169e5aec4 100644 --- a/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml +++ b/deploy/cloudformation/elastic-agent-direct-access-key-cspm.yml @@ -1,38 +1,38 @@ AWSTemplateFormatVersion: "2010-09-09" + Description: Creates elastic-agent cspm user, role, and access key, and outputs the access key Parameters: {} Resources: ElasticCSPMUser: - Type: "AWS::IAM::User" + Type: AWS::IAM::User Properties: UserName: !Join - '-' - - - 'elasticagent-user-cspm' + - - elasticagent-user-cspm - !Select - 2 - !Split - / - !Ref AWS::StackId ManagedPolicyArns: - - 'arn:aws:iam::aws:policy/SecurityAudit' + - arn:aws:iam::aws:policy/SecurityAudit ElasticCSPMAccessKey: - Type: "AWS::IAM::AccessKey" + Type: AWS::IAM::AccessKey Properties: UserName: !Ref ElasticCSPMUser Outputs: AccessKeyId: - Description: "Access Key ID" + Description: Access Key ID Value: !Ref ElasticCSPMAccessKey Export: - Name: "AccessKeyId" + Name: AccessKeyId SecretAccessKey: - Description: "Secret Access Key" + Description: Secret Access Key Value: !GetAtt ElasticCSPMAccessKey.SecretAccessKey Export: - Name: "SecretAccessKey" - + Name: SecretAccessKey