From 1573fcecbc50c9237addc04980a54f39a64cf015 Mon Sep 17 00:00:00 2001 From: Ryan Payne Date: Wed, 23 Oct 2024 11:11:07 -0500 Subject: [PATCH] FEATURE: EKS Protection (#61) * codebuild source * lambda source * templates * documentation * vpcid * architecture diagram * extend orgid function * handle delete * remove pptx * lint python * resolve comments * pylint * add eks test * default values * move codebuild package * fix checkov comment * codebuild package path * fix subs * orgid function * eb account conditional * data var * missing comma * Update entrypoint.sh * checkov skip * bugfix ssm action * lambda descriptions * minor version --------- Co-authored-by: Kishore Vinjam --- .../functional_tests/entrypoint.sh | 4 + .taskcat.yml | 14 + VERSION | 2 +- codebuild/source/buildspec.yml | 34 ++ codebuild/source/falcon_admission.yaml | 11 + codebuild/source/install_sensor_fargate.sh | 57 ++ codebuild/source/install_sensor_nodegroup.sh | 65 +++ codebuild/source/kpa_config.value | 10 + codebuild/source/node_sensor.yaml | 14 + codebuild/source/node_sensor_ecr.yaml | 21 + codebuild/source/setup_cluster.py | 116 ++++ codebuild/source/setup_images.sh | 36 ++ codebuild/source/setup_manifests.sh | 28 + codebuild/source/sidecar_sensor.yaml | 14 + guide/content/architecture.md | 38 +- guide/content/deployment-steps.md | 15 + guide/content/images/eks-protect-diagram.png | Bin 0 -> 136146 bytes .../source/codebuild/buildspec.yml | 34 ++ .../source/codebuild/falcon_admission.yaml | 11 + .../codebuild/install_sensor_fargate.sh | 57 ++ .../codebuild/install_sensor_nodegroup.sh | 65 +++ .../source/codebuild/kpa_config.value | 10 + .../source/codebuild/node_sensor.yaml | 14 + .../source/codebuild/node_sensor_ecr.yaml | 21 + .../source/codebuild/setup_cluster.py | 116 ++++ .../source/codebuild/setup_images.sh | 36 ++ .../source/codebuild/setup_manifests.sh | 28 + .../source/codebuild/sidecar_sensor.yaml | 14 + .../source/cw-helper/organizations.py | 29 +- .../source/eks-existing-clusters/lambda.py | 253 ++++++++ .../eks-existing-clusters/requirements.txt | 2 + .../source/eks-new-clusters/lambda.py | 121 ++++ .../source/register-organization/lambda.py | 138 +++-- .../aws_cspm_cloudformation_ioa_comm_gov.json | 14 +- templates/crowdstrike_init_stack.yaml | 285 ++++++++- templates/eks-eventbridge-stackset.yml | 35 ++ templates/eks-protection-stack.yml | 543 ++++++++++++++++++ templates/eks-root-roles.yml | 237 ++++++++ templates/eks-target-roles-stackset.yml | 113 ++++ 39 files changed, 2568 insertions(+), 87 deletions(-) create mode 100644 codebuild/source/buildspec.yml create mode 100644 codebuild/source/falcon_admission.yaml create mode 100755 codebuild/source/install_sensor_fargate.sh create mode 100755 codebuild/source/install_sensor_nodegroup.sh create mode 100644 codebuild/source/kpa_config.value create mode 100644 codebuild/source/node_sensor.yaml create mode 100644 codebuild/source/node_sensor_ecr.yaml create mode 100644 codebuild/source/setup_cluster.py create mode 100644 codebuild/source/setup_images.sh create mode 100644 codebuild/source/setup_manifests.sh create mode 100644 codebuild/source/sidecar_sensor.yaml create mode 100644 guide/content/images/eks-protect-diagram.png create mode 100644 lambda_functions/source/codebuild/buildspec.yml create mode 100644 lambda_functions/source/codebuild/falcon_admission.yaml create mode 100755 lambda_functions/source/codebuild/install_sensor_fargate.sh create mode 100755 lambda_functions/source/codebuild/install_sensor_nodegroup.sh create mode 100644 lambda_functions/source/codebuild/kpa_config.value create mode 100644 lambda_functions/source/codebuild/node_sensor.yaml create mode 100644 lambda_functions/source/codebuild/node_sensor_ecr.yaml create mode 100644 lambda_functions/source/codebuild/setup_cluster.py create mode 100644 lambda_functions/source/codebuild/setup_images.sh create mode 100644 lambda_functions/source/codebuild/setup_manifests.sh create mode 100644 lambda_functions/source/codebuild/sidecar_sensor.yaml create mode 100644 lambda_functions/source/eks-existing-clusters/lambda.py create mode 100644 lambda_functions/source/eks-existing-clusters/requirements.txt create mode 100644 lambda_functions/source/eks-new-clusters/lambda.py create mode 100644 templates/eks-eventbridge-stackset.yml create mode 100644 templates/eks-protection-stack.yml create mode 100644 templates/eks-root-roles.yml create mode 100644 templates/eks-target-roles-stackset.yml diff --git a/.project_automation/functional_tests/entrypoint.sh b/.project_automation/functional_tests/entrypoint.sh index dc6068a..fda5377 100755 --- a/.project_automation/functional_tests/entrypoint.sh +++ b/.project_automation/functional_tests/entrypoint.sh @@ -41,6 +41,10 @@ run_test() { # Run taskcat e2e test run_test "cw-test" +run_test "cw-test-sra" + +run_test "cw-eks-test" + run_test "cw-test-ct" run_test "cw-test-ssm" diff --git a/.taskcat.yml b/.taskcat.yml index 5837eb0..c249bf1 100644 --- a/.taskcat.yml +++ b/.taskcat.yml @@ -18,6 +18,20 @@ tests: regions: - us-east-1 template: templates/crowdstrike_init_stack.yaml + cw-eks-test: + parameters: + FalconClientID: $[taskcat_ssm_/crowdstrike/falcon_client_id] + FalconSecret: $[taskcat_ssm_/crowdstrike/falcon_secret] + DockerAPIToken: $[taskcat_ssm_/crowdstrike/falcon_docker_api_token] + FalconCID: $[taskcat_ssm_/crowdstrike/falcon_cod] + EventBusAccount: $[taskcat_ssm_/crowdstrike/eventbus_account] + SourceS3BucketName: $[taskcat_autobucket] + S3BucketRegion: $[taskcat_current_region] + ProvisionOU: $[taskcat_ssm_/crowdstrike/provision-ou] + ExcludeRegions: $[taskcat_ssm_/crowdstrike/exclude_regions] + regions: + - us-east-1 + template: templates/crowdstrike_init_stack.yaml cw-test-trail: parameters: FalconClientID: $[taskcat_ssm_/crowdstrike/falcon_client_id] diff --git a/VERSION b/VERSION index 0ec25f7..795460f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.0.0 +v1.1.0 diff --git a/codebuild/source/buildspec.yml b/codebuild/source/buildspec.yml new file mode 100644 index 0000000..6fcf728 --- /dev/null +++ b/codebuild/source/buildspec.yml @@ -0,0 +1,34 @@ +version: 0.2 + +phases: + install: + on-failure: ABORT + commands: + - echo "Installing Prerequisites" + - apt-get -qq update + - apt-get -qq install -y python3 + - apt-get -qq install -y python3-pip + - pip3 install boto3 --quiet + - pip3 install botocore --quiet + - curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.28.5/2024-01-04/bin/linux/amd64/kubectl + - chmod +x ./kubectl + - mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH + - curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + - helm repo add crowdstrike https://crowdstrike.github.io/falcon-helm && helm repo update + - ARCH=amd64 + - PLATFORM=$(uname -s)_$ARCH + - curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz" + - tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz + - mv /tmp/eksctl /usr/local/bin + pre_build: + on-failure: ABORT + commands: + - python3 setup_cluster.py + - chmod +x setup_images.sh && ./setup_images.sh + - . /root/.bashrc + - chmod +x setup_manifests.sh && ./setup_manifests.sh + build: + on-failure: ABORT + commands: + - chmod +x install_sensor_$NODE_TYPE.sh + - ./install_sensor_$NODE_TYPE.sh \ No newline at end of file diff --git a/codebuild/source/falcon_admission.yaml b/codebuild/source/falcon_admission.yaml new file mode 100644 index 0000000..7663ff5 --- /dev/null +++ b/codebuild/source/falcon_admission.yaml @@ -0,0 +1,11 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconAdmission +metadata: + name: falcon-admission +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + registry: + type: REGISTRY diff --git a/codebuild/source/install_sensor_fargate.sh b/codebuild/source/install_sensor_fargate.sh new file mode 100755 index 0000000..025ada0 --- /dev/null +++ b/codebuild/source/install_sensor_fargate.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${SWITCH_ROLE} +OUT=$(aws sts assume-role --role-arn $role_arn --role-session-name crowdstrike-eks-codebuild);\ +export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials''.AccessKeyId');\ +export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials''.SecretAccessKey');\ +export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials''.SessionToken'); + +echo "Creating kubeconfig for $CLUSTER" +aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER + +export AWS_ACCESS_KEY_ID="" +export AWS_SECRET_ACCESS_KEY="" +export AWS_SESSION_TOKEN="" + +pods=$(kubectl get pods -A) +case "$pods" in + *kpagent*) + echo "Protection Agent already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Protection Agent..." + helm upgrade --install -f kpa_config.value --create-namespace -n falcon-kubernetes-protection kpagent crowdstrike/cs-k8s-protection-agent + ;; +esac +case "$pods" in + *falcon-operator*) + echo "Operator already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Operator..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-operator --namespace falcon-operator + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + ;; +esac +case "$pods" in + *falcon-sidecar-sensor*) + echo "Sensor already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing sensor..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-system --namespace falcon-system + kubectl create -f sidecar_sensor.yaml + ;; +esac +if [ $ENABLE_KAC == "true" ]; then + case "$pods" in + *falcon-admission*) + echo "Admission Controller already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Admission Controller..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-kac --namespace falcon-kac + kubectl create -f falcon_admission.yaml + ;; + esac +fi diff --git a/codebuild/source/install_sensor_nodegroup.sh b/codebuild/source/install_sensor_nodegroup.sh new file mode 100755 index 0000000..c672fff --- /dev/null +++ b/codebuild/source/install_sensor_nodegroup.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${SWITCH_ROLE} +OUT=$(aws sts assume-role --role-arn $role_arn --role-session-name crowdstrike-eks-codebuild);\ +export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials''.AccessKeyId');\ +export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials''.SecretAccessKey');\ +export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials''.SessionToken'); + +echo "Creating kubeconfig for $CLUSTER" +aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER + +export AWS_ACCESS_KEY_ID="" +export AWS_SECRET_ACCESS_KEY="" +export AWS_SESSION_TOKEN="" + +pods=$(kubectl get pods -A) +case "$pods" in + *kpagent*) + echo "Protection Agent already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Protection Agent..." + helm upgrade --install -f kpa_config.value --create-namespace -n falcon-kubernetes-protection kpagent crowdstrike/cs-k8s-protection-agent + ;; +esac +case "$pods" in + *falcon-operator*) + echo "Operator already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Operator..." + if [ $REGISTRY == "ecr" ]; then + eksctl utils associate-iam-oidc-provider --region $AWS_REGION --cluster $CLUSTER --approve + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + kubectl set env -n falcon-operator deployment/falcon-operator-controller-manager AWS_REGION=$IMAGE_REGION + else + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + fi + ;; +esac +case "$pods" in + *falcon-node-sensor*) + echo "Sensor already installed on cluster: $CLUSTER" + ;; + *) + + echo "Installing node sensor..." + if [ $REGISTRY == "ecr" ]; then + kubectl create -f node_sensor_ecr.yaml + else + kubectl create -f node_sensor.yaml + fi + ;; +esac +if [ $ENABLE_KAC == "true" ]; then + case "$pods" in + *falcon-admission*) + echo "Admission Controller already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Admission Controller..." + kubectl create -f falcon_admission.yaml + ;; + esac +fi diff --git a/codebuild/source/kpa_config.value b/codebuild/source/kpa_config.value new file mode 100644 index 0000000..09d2fac --- /dev/null +++ b/codebuild/source/kpa_config.value @@ -0,0 +1,10 @@ +image: + repository: KPA_URI + tag: KPA_TAG +crowdstrikeConfig: + clientID: FALCON_CLIENT_ID + clientSecret: FALCON_CLIENT_SECRET + clusterName: CLUSTER_ARN + env: CROWDSTRIKE_CLOUD + cid: CID_LOWER + dockerAPIToken: DOCKER_API_TOKEN diff --git a/codebuild/source/node_sensor.yaml b/codebuild/source/node_sensor.yaml new file mode 100644 index 0000000..43e436e --- /dev/null +++ b/codebuild/source/node_sensor.yaml @@ -0,0 +1,14 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconNodeSensor +metadata: + name: falcon-node-sensor +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + node: + backend: BACKEND + falcon: + tags: + - daemonset \ No newline at end of file diff --git a/codebuild/source/node_sensor_ecr.yaml b/codebuild/source/node_sensor_ecr.yaml new file mode 100644 index 0000000..3ca423b --- /dev/null +++ b/codebuild/source/node_sensor_ecr.yaml @@ -0,0 +1,21 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconNodeSensor +metadata: + labels: + crowdstrike.com/component: sample + crowdstrike.com/created-by: falcon-operator + crowdstrike.com/instance: falcon-node-sensor + crowdstrike.com/managed-by: kustomize + crowdstrike.com/name: falconnodesensor + crowdstrike.com/part-of: Falcon + crowdstrike.com/provider: crowdstrike + name: falcon-node-sensor +spec: + node: + backend: BACKEND + image: NODE_SENSOR_URI:NODE_SENSOR_TAG + falcon: + cid: CID + trace: none + tags: + - daemonset \ No newline at end of file diff --git a/codebuild/source/setup_cluster.py b/codebuild/source/setup_cluster.py new file mode 100644 index 0000000..eb74b02 --- /dev/null +++ b/codebuild/source/setup_cluster.py @@ -0,0 +1,116 @@ +import os +import time +import boto3 +import botocore + +AWS_REGION = os.environ['AWS_REGION'] +PRINCIPAL_ARN = os.environ['PRINCIPAL_ARN'] +USERNAME = os.environ['USERNAME'] +CLUSTER = os.environ['CLUSTER'] +NODETYPE = os.environ['NODE_TYPE'] +ACCOUNT_ID = os.environ['ACCOUNT_ID'] +REGION = os.environ['REGION'] +SWITCH_ROLE = os.environ['SWITCH_ROLE'] +NAT_IP = os.environ['NAT_IP'] +ACCESS_POLICY = 'arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy' + +def check_cluster(session): + client = session.client( + service_name='eks', + region_name=AWS_REGION + ) + + cluster_details = client.describe_cluster( + name=CLUSTER + ) + public_access_cidrs = cluster_details.get('cluster', {}).get('resourcesVpcConfig', {}).get('publicAccessCidrs') + while 'ACTIVE' not in cluster_details.get('cluster', {}).get('status'): + time.sleep(60) + cluster_details = client.describe_cluster( + name=CLUSTER + ) + else: + print(f'Cluster {CLUSTER} is now active') + return public_access_cidrs + +def setup_cluster(session, public_access_cidrs): + client = session.client( + service_name='eks', + region_name=AWS_REGION + ) + + try: + print(f'Adding access entry for {CLUSTER}') + client.create_access_entry( + clusterName=CLUSTER, + principalArn=PRINCIPAL_ARN, + username=USERNAME, + type='STANDARD' + ) + + except botocore.exceptions.ClientError as error: + if error.response['Error']['Code'] == "ResourceInUseException": + print(f'Skipping Access Entry for {CLUSTER}: {PRINCIPAL_ARN} already exists') + else: + print(error) + try: + print(f'Adding access policy for {CLUSTER}') + client.associate_access_policy( + clusterName=CLUSTER, + principalArn=PRINCIPAL_ARN, + policyArn=ACCESS_POLICY, + accessScope={ + 'type': 'cluster' + } + ) + except botocore.exceptions.ClientError as error: + print(error) + try: + print(f'Adding NAT IP for {CLUSTER}') + public_access_cidrs.append(f'{NAT_IP}/32') + response = session.update_cluster_config( + name=CLUSTER, + resourcesVpcConfig={ + 'publicAccessCidrs': public_access_cidrs + } + ) + update_id = response['update']['id'] + update_response = client.describe_update( + name=CLUSTER, + updateId=update_id + ) + while update_response['update']['status'] in 'InProgress': + print('waiting for update to complete...') + time.sleep(30) + update_response = client.describe_update( + name=CLUSTER, + updateId=update_id + ) + except botocore.exceptions.ClientError as error: + print(error) + print(f'Cluster: {CLUSTER} is now setup') + return + +def new_session(): + try: + sts_connection = boto3.client('sts') + credentials = sts_connection.assume_role( + RoleArn=f'arn:aws:iam::{ACCOUNT_ID}:role/{SWITCH_ROLE}', + RoleSessionName=f'crowdstrike-eks-{ACCOUNT_ID}' + ) + return boto3.session.Session( + aws_access_key_id=credentials['Credentials']['AccessKeyId'], + aws_secret_access_key=credentials['Credentials']['SecretAccessKey'], + aws_session_token=credentials['Credentials']['SessionToken'], + region_name=REGION + ) + except sts_connection.exceptions.ClientError as exc: + # Print the error and continue. + # Handle what to do with accounts that cannot be accessed + # due to assuming role errors. + print("Cannot access adjacent account: ", ACCOUNT_ID, exc) + return None + +session = new_session() +public_access_cidrs = check_cluster(session) +setup_cluster(session, public_access_cidrs) \ No newline at end of file diff --git a/codebuild/source/setup_images.sh b/codebuild/source/setup_images.sh new file mode 100644 index 0000000..71a4737 --- /dev/null +++ b/codebuild/source/setup_images.sh @@ -0,0 +1,36 @@ +#!/bin/bash +echo "Registry is $REGISTRY" +if [ $REGISTRY == "ecr" ]; then + + echo "Getting ECR login..." + aws ecr get-login-password --region $IMAGE_REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com + ecr_uri="$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/crowdstrike" + + echo "Pushing Node Sensor image..." + + node_sensor_repo="crowdstrike/falcon-sensor" + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'falcon-sensor' -c $ecr_uri + echo "export NODE_SENSOR_URI=$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/$node_sensor_repo" >> /root/.bashrc + node_sensor_tag=$(aws ecr list-images --repository-name $node_sensor_repo --query 'imageIds[*].imageTag' --output text) + echo "export NODE_SENSOR_TAG=$node_sensor_tag" >> /root/.bashrc + + echo "Pushing KPA image..." + + kpa_repo="crowdstrike/kpagent" + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'kpagent' -c $ecr_uri + echo "export KPA_URI=$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/$kpa_repo" >> /root/.bashrc + kpa_tag=$(aws ecr list-images --repository-name $kpa_repo --query 'imageIds[*].imageTag' --output text) + echo "export KPA_TAG=$kpa_tag" >> /root/.bashrc + +elif [ $REGISTRY == "crowdstrike" ]; then + + echo "Getting KPA image..." + + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'kpagent' + echo "export KPA_URI=registry.crowdstrike.com/kubernetes_protection/kpagent" >> /root/.bashrc + kpa_tag=$(docker images registry.crowdstrike.com/kubernetes_protection/kpagent --format "{{.Tag}}") + echo "export KPA_TAG=$kpa_tag" >> /root/.bashrc + +else + echo "Missing env variable REGISTRY" +fi \ No newline at end of file diff --git a/codebuild/source/setup_manifests.sh b/codebuild/source/setup_manifests.sh new file mode 100644 index 0000000..13e8693 --- /dev/null +++ b/codebuild/source/setup_manifests.sh @@ -0,0 +1,28 @@ +#!/bin/bash +CID_LOWER=$(echo $CID | cut -d '-' -f 1 | tr '[:upper:]' '[:lower:]') +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" kpa_config.value +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" kpa_config.value +sed -i "s~KPA_URI~$KPA_URI~" kpa_config.value +sed -i "s~KPA_TAG~$KPA_TAG~" kpa_config.value +sed -i "s~CLUSTER_ARN~$CLUSTER_ARN~" kpa_config.value +sed -i "s~CROWDSTRIKE_CLOUD~$CROWDSTRIKE_CLOUD~" kpa_config.value +sed -i "s~CID_LOWER~$CID_LOWER~" kpa_config.value +sed -i "s~DOCKER_API_TOKEN~$DOCKER_API_TOKEN~" kpa_config.value + +if [ $REGISTRY == "ecr" ]; then + sed -i "s~NODE_SENSOR_URI~$NODE_SENSOR_URI~" node_sensor_ecr.yaml + sed -i "s~NODE_SENSOR_TAG~$NODE_SENSOR_TAG~" node_sensor_ecr.yaml + sed -i "s~BACKEND~$BACKEND~" node_sensor_ecr.yaml + sed -i "s~CID~$CID~" node_sensor_ecr.yaml +elif [ $REGISTRY == "crowdstrike" ]; then + sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" node_sensor.yaml + sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" node_sensor.yaml + sed -i "s~BACKEND~$BACKEND~" node_sensor.yaml +fi + +sed -i "s~REGISTRY~$REGISTRY~" sidecar_sensor.yaml +sed -i "s~REGISTRY~$REGISTRY~" falcon_admission.yaml +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" sidecar_sensor.yaml +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" sidecar_sensor.yaml +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" falcon_admission.yaml +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" falcon_admission.yaml diff --git a/codebuild/source/sidecar_sensor.yaml b/codebuild/source/sidecar_sensor.yaml new file mode 100644 index 0000000..4d9d113 --- /dev/null +++ b/codebuild/source/sidecar_sensor.yaml @@ -0,0 +1,14 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconContainer +metadata: + name: falcon-sidecar-sensor +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + registry: + type: REGISTRY + injector: + disableDefaultNamespaceInjection: true + disableDefaultPodInjection: true \ No newline at end of file diff --git a/guide/content/architecture.md b/guide/content/architecture.md index 6c63fcf..4d6cf5e 100644 --- a/guide/content/architecture.md +++ b/guide/content/architecture.md @@ -6,13 +6,10 @@ description: Solution architecture. Deploying this ABI solution with default parameters builds the following architecture. -![CSPM Architecture diagram](/images/cspm_architecture.png) - -![SSM Distributor Architecture diagram](/images/distributor_architecture.png) - -![Sensor Management Architecture diagram](/images/sensor_architecture.png) - -As shown in the diagram, the solution sets up the following: +### CSPM Architecture +![CSPM Architecture diagram](/images/cspm_architecture.png) +### Sensor Management (OneClick) +![Sensor Management Architecture diagram](/images/sensor_architecture.png) * In all current accounts in your AWS organization: * IAM role that allows CrowdStrike to perform read-only activities. @@ -40,4 +37,31 @@ As shown in the diagram, the solution sets up the following: * IAM role that allows SSM Associations to retrive API Credentials from Secrets Manager. * SSM Associations to deploy Falcon Sensor via SSM Distributor Package against SSM-Managed instances. +### SSM Distributor +![SSM Distributor Architecture diagram](/images/distributor_architecture.png) +* In the child AWS accounts: + * Secrets Manager Secret to manage CrowdStrike API Credentials. + * IAM role that allows SSM Associations to retrive API Credentials from Secrets Manager. + * SSM Associations to deploy Falcon Sensor via SSM Distributor Package against SSM-Managed instances. + +### EKS Protection +![EKS Protection Diagram](/images/eks-protect-diagram.png) +* If you enable EKS Protection: + * In the centralized account: + * IAM Role for EventBridge to trigger Lambda + * IAM Role for Lambda Execution + * IAM Role for CodeBuild Execution + * EventBus to receive cluster events + * EventBridge Rule to trigger Lambda + * Lambda functions to process cluster events and trigger Codebuild + * CodeBuild project to apply Falcon Operator to EKS Clusters + * Secret to store Falcon API key + * Optional ECR repositories if registry = ecr + * VPC, NAT, EIP for CodeBuild project + * In the child accounts: + * IAM Role for EventBridge to trigger Lambda + * IAM Role for Lambda Execution + * IAM Role for CodeBuild Execution + * EventBridge Rule to send cluster events to centralized EventBus + **Next:** Choose [Deployment options](/deployment-options/index.html). \ No newline at end of file diff --git a/guide/content/deployment-steps.md b/guide/content/deployment-steps.md index 6c5338e..7f23c79 100644 --- a/guide/content/deployment-steps.md +++ b/guide/content/deployment-steps.md @@ -56,6 +56,21 @@ description: Deployment steps. * **Governed Regions**: If Create Default Org Trail = true: for AWS Control Tower, set to ct-regions (default). If not using AWS Control Tower, specify comma separated list of regions (e.g. us-west-2,us-east-1,ap-south-1) in lower case. * **Security Account Id**: If Create Default Org Trail = true: AWS Account ID of the Security Tooling account (ignored for AWS Control Tower environments). * **Log Archive Account Id**: If Create Default Org Trail = true: AWS Account ID of the Log Archive account (ignored for AWS Control Tower environments). + * EKS Protection + * **EKSProtection**: Enable CrowdStrike EKS Protection to automatically deploy Falcon Sensor against EKS Clusters. Allowed values include `true` or `false`. Default is `false` + * **FalconCID**: Your CrowdStrike Falcon CID with checksum. (eg. ********************************-ab) + * **DockerAPIToken**: Your Falcon Docker API Token + * **OrganizationId**: Your AWS Organization ID (eg. o-********) + * **EventBusAccount**: The account to centralize EKS Protection resources. This account must be the Organization Management Account or a Delegated Administrator. + * **EventBusName**: Name of the centralized EventBus. Default is `crowdstrike-eks-eventbus` + * **EventBridgeRoleName**: Name of the EventBridge IAM role. Default is `crowdstrike-eks-eventbridge-role` + * **EKSExecutionRoleName**: Name of the Target Execution IAM role. Default is `crowdstrike-eks-execution-role` + * **CodeBuildRoleName**: Name of the CodeBuild IAM role. Default is `crowdstrike-eks-codebuild-role` + * **CodeBuildProjectName**: Name of the CodeBuild Project. Default is `crowdstrike-eks-codebuild` + * **KubernetesUserName**: Name of the Kubernetes UserName. Default is `crowdstrike-eks` + * **Registry**: Source Falcon Image from CrowdStrike or mirror to ECR. Allowed values are `crowdstrike` or `ecr`. Default is `crowdstrike` + * **Backend**: kernel or bpf for Daemonset Sensor. Allowed Values are `kernel` or `bpf`. Default is `kernel` + * **EnableKAC**: Deploy Kubernetes Admission Controller (KAC). For more info see https://falcon.crowdstrike.com/documentation/page/aa4fccee/container-security#s41cbec3 3. Select both of the following capabilities and choose **Submit** to launch the stack. diff --git a/guide/content/images/eks-protect-diagram.png b/guide/content/images/eks-protect-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd88bd197dd96f1553dab8a6c417942da855ece GIT binary patch literal 136146 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 Xj?O#f#Ob6B13w1GO?B=ca|-_-9T+6% literal 0 HcmV?d00001 diff --git a/lambda_functions/source/codebuild/buildspec.yml b/lambda_functions/source/codebuild/buildspec.yml new file mode 100644 index 0000000..6fcf728 --- /dev/null +++ b/lambda_functions/source/codebuild/buildspec.yml @@ -0,0 +1,34 @@ +version: 0.2 + +phases: + install: + on-failure: ABORT + commands: + - echo "Installing Prerequisites" + - apt-get -qq update + - apt-get -qq install -y python3 + - apt-get -qq install -y python3-pip + - pip3 install boto3 --quiet + - pip3 install botocore --quiet + - curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.28.5/2024-01-04/bin/linux/amd64/kubectl + - chmod +x ./kubectl + - mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH + - curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + - helm repo add crowdstrike https://crowdstrike.github.io/falcon-helm && helm repo update + - ARCH=amd64 + - PLATFORM=$(uname -s)_$ARCH + - curl -sLO "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz" + - tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp && rm eksctl_$PLATFORM.tar.gz + - mv /tmp/eksctl /usr/local/bin + pre_build: + on-failure: ABORT + commands: + - python3 setup_cluster.py + - chmod +x setup_images.sh && ./setup_images.sh + - . /root/.bashrc + - chmod +x setup_manifests.sh && ./setup_manifests.sh + build: + on-failure: ABORT + commands: + - chmod +x install_sensor_$NODE_TYPE.sh + - ./install_sensor_$NODE_TYPE.sh \ No newline at end of file diff --git a/lambda_functions/source/codebuild/falcon_admission.yaml b/lambda_functions/source/codebuild/falcon_admission.yaml new file mode 100644 index 0000000..7663ff5 --- /dev/null +++ b/lambda_functions/source/codebuild/falcon_admission.yaml @@ -0,0 +1,11 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconAdmission +metadata: + name: falcon-admission +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + registry: + type: REGISTRY diff --git a/lambda_functions/source/codebuild/install_sensor_fargate.sh b/lambda_functions/source/codebuild/install_sensor_fargate.sh new file mode 100755 index 0000000..025ada0 --- /dev/null +++ b/lambda_functions/source/codebuild/install_sensor_fargate.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${SWITCH_ROLE} +OUT=$(aws sts assume-role --role-arn $role_arn --role-session-name crowdstrike-eks-codebuild);\ +export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials''.AccessKeyId');\ +export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials''.SecretAccessKey');\ +export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials''.SessionToken'); + +echo "Creating kubeconfig for $CLUSTER" +aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER + +export AWS_ACCESS_KEY_ID="" +export AWS_SECRET_ACCESS_KEY="" +export AWS_SESSION_TOKEN="" + +pods=$(kubectl get pods -A) +case "$pods" in + *kpagent*) + echo "Protection Agent already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Protection Agent..." + helm upgrade --install -f kpa_config.value --create-namespace -n falcon-kubernetes-protection kpagent crowdstrike/cs-k8s-protection-agent + ;; +esac +case "$pods" in + *falcon-operator*) + echo "Operator already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Operator..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-operator --namespace falcon-operator + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + ;; +esac +case "$pods" in + *falcon-sidecar-sensor*) + echo "Sensor already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing sensor..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-system --namespace falcon-system + kubectl create -f sidecar_sensor.yaml + ;; +esac +if [ $ENABLE_KAC == "true" ]; then + case "$pods" in + *falcon-admission*) + echo "Admission Controller already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Admission Controller..." + eksctl create fargateprofile --region $AWS_REGION --cluster $CLUSTER --name fp-falcon-kac --namespace falcon-kac + kubectl create -f falcon_admission.yaml + ;; + esac +fi diff --git a/lambda_functions/source/codebuild/install_sensor_nodegroup.sh b/lambda_functions/source/codebuild/install_sensor_nodegroup.sh new file mode 100755 index 0000000..c672fff --- /dev/null +++ b/lambda_functions/source/codebuild/install_sensor_nodegroup.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${SWITCH_ROLE} +OUT=$(aws sts assume-role --role-arn $role_arn --role-session-name crowdstrike-eks-codebuild);\ +export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials''.AccessKeyId');\ +export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials''.SecretAccessKey');\ +export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials''.SessionToken'); + +echo "Creating kubeconfig for $CLUSTER" +aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER + +export AWS_ACCESS_KEY_ID="" +export AWS_SECRET_ACCESS_KEY="" +export AWS_SESSION_TOKEN="" + +pods=$(kubectl get pods -A) +case "$pods" in + *kpagent*) + echo "Protection Agent already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Protection Agent..." + helm upgrade --install -f kpa_config.value --create-namespace -n falcon-kubernetes-protection kpagent crowdstrike/cs-k8s-protection-agent + ;; +esac +case "$pods" in + *falcon-operator*) + echo "Operator already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Operator..." + if [ $REGISTRY == "ecr" ]; then + eksctl utils associate-iam-oidc-provider --region $AWS_REGION --cluster $CLUSTER --approve + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + kubectl set env -n falcon-operator deployment/falcon-operator-controller-manager AWS_REGION=$IMAGE_REGION + else + kubectl apply -f https://github.com/CrowdStrike/falcon-operator/releases/latest/download/falcon-operator.yaml + fi + ;; +esac +case "$pods" in + *falcon-node-sensor*) + echo "Sensor already installed on cluster: $CLUSTER" + ;; + *) + + echo "Installing node sensor..." + if [ $REGISTRY == "ecr" ]; then + kubectl create -f node_sensor_ecr.yaml + else + kubectl create -f node_sensor.yaml + fi + ;; +esac +if [ $ENABLE_KAC == "true" ]; then + case "$pods" in + *falcon-admission*) + echo "Admission Controller already installed on cluster: $CLUSTER" + ;; + *) + echo "Installing Admission Controller..." + kubectl create -f falcon_admission.yaml + ;; + esac +fi diff --git a/lambda_functions/source/codebuild/kpa_config.value b/lambda_functions/source/codebuild/kpa_config.value new file mode 100644 index 0000000..09d2fac --- /dev/null +++ b/lambda_functions/source/codebuild/kpa_config.value @@ -0,0 +1,10 @@ +image: + repository: KPA_URI + tag: KPA_TAG +crowdstrikeConfig: + clientID: FALCON_CLIENT_ID + clientSecret: FALCON_CLIENT_SECRET + clusterName: CLUSTER_ARN + env: CROWDSTRIKE_CLOUD + cid: CID_LOWER + dockerAPIToken: DOCKER_API_TOKEN diff --git a/lambda_functions/source/codebuild/node_sensor.yaml b/lambda_functions/source/codebuild/node_sensor.yaml new file mode 100644 index 0000000..43e436e --- /dev/null +++ b/lambda_functions/source/codebuild/node_sensor.yaml @@ -0,0 +1,14 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconNodeSensor +metadata: + name: falcon-node-sensor +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + node: + backend: BACKEND + falcon: + tags: + - daemonset \ No newline at end of file diff --git a/lambda_functions/source/codebuild/node_sensor_ecr.yaml b/lambda_functions/source/codebuild/node_sensor_ecr.yaml new file mode 100644 index 0000000..3ca423b --- /dev/null +++ b/lambda_functions/source/codebuild/node_sensor_ecr.yaml @@ -0,0 +1,21 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconNodeSensor +metadata: + labels: + crowdstrike.com/component: sample + crowdstrike.com/created-by: falcon-operator + crowdstrike.com/instance: falcon-node-sensor + crowdstrike.com/managed-by: kustomize + crowdstrike.com/name: falconnodesensor + crowdstrike.com/part-of: Falcon + crowdstrike.com/provider: crowdstrike + name: falcon-node-sensor +spec: + node: + backend: BACKEND + image: NODE_SENSOR_URI:NODE_SENSOR_TAG + falcon: + cid: CID + trace: none + tags: + - daemonset \ No newline at end of file diff --git a/lambda_functions/source/codebuild/setup_cluster.py b/lambda_functions/source/codebuild/setup_cluster.py new file mode 100644 index 0000000..eb74b02 --- /dev/null +++ b/lambda_functions/source/codebuild/setup_cluster.py @@ -0,0 +1,116 @@ +import os +import time +import boto3 +import botocore + +AWS_REGION = os.environ['AWS_REGION'] +PRINCIPAL_ARN = os.environ['PRINCIPAL_ARN'] +USERNAME = os.environ['USERNAME'] +CLUSTER = os.environ['CLUSTER'] +NODETYPE = os.environ['NODE_TYPE'] +ACCOUNT_ID = os.environ['ACCOUNT_ID'] +REGION = os.environ['REGION'] +SWITCH_ROLE = os.environ['SWITCH_ROLE'] +NAT_IP = os.environ['NAT_IP'] +ACCESS_POLICY = 'arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy' + +def check_cluster(session): + client = session.client( + service_name='eks', + region_name=AWS_REGION + ) + + cluster_details = client.describe_cluster( + name=CLUSTER + ) + public_access_cidrs = cluster_details.get('cluster', {}).get('resourcesVpcConfig', {}).get('publicAccessCidrs') + while 'ACTIVE' not in cluster_details.get('cluster', {}).get('status'): + time.sleep(60) + cluster_details = client.describe_cluster( + name=CLUSTER + ) + else: + print(f'Cluster {CLUSTER} is now active') + return public_access_cidrs + +def setup_cluster(session, public_access_cidrs): + client = session.client( + service_name='eks', + region_name=AWS_REGION + ) + + try: + print(f'Adding access entry for {CLUSTER}') + client.create_access_entry( + clusterName=CLUSTER, + principalArn=PRINCIPAL_ARN, + username=USERNAME, + type='STANDARD' + ) + + except botocore.exceptions.ClientError as error: + if error.response['Error']['Code'] == "ResourceInUseException": + print(f'Skipping Access Entry for {CLUSTER}: {PRINCIPAL_ARN} already exists') + else: + print(error) + try: + print(f'Adding access policy for {CLUSTER}') + client.associate_access_policy( + clusterName=CLUSTER, + principalArn=PRINCIPAL_ARN, + policyArn=ACCESS_POLICY, + accessScope={ + 'type': 'cluster' + } + ) + except botocore.exceptions.ClientError as error: + print(error) + try: + print(f'Adding NAT IP for {CLUSTER}') + public_access_cidrs.append(f'{NAT_IP}/32') + response = session.update_cluster_config( + name=CLUSTER, + resourcesVpcConfig={ + 'publicAccessCidrs': public_access_cidrs + } + ) + update_id = response['update']['id'] + update_response = client.describe_update( + name=CLUSTER, + updateId=update_id + ) + while update_response['update']['status'] in 'InProgress': + print('waiting for update to complete...') + time.sleep(30) + update_response = client.describe_update( + name=CLUSTER, + updateId=update_id + ) + except botocore.exceptions.ClientError as error: + print(error) + print(f'Cluster: {CLUSTER} is now setup') + return + +def new_session(): + try: + sts_connection = boto3.client('sts') + credentials = sts_connection.assume_role( + RoleArn=f'arn:aws:iam::{ACCOUNT_ID}:role/{SWITCH_ROLE}', + RoleSessionName=f'crowdstrike-eks-{ACCOUNT_ID}' + ) + return boto3.session.Session( + aws_access_key_id=credentials['Credentials']['AccessKeyId'], + aws_secret_access_key=credentials['Credentials']['SecretAccessKey'], + aws_session_token=credentials['Credentials']['SessionToken'], + region_name=REGION + ) + except sts_connection.exceptions.ClientError as exc: + # Print the error and continue. + # Handle what to do with accounts that cannot be accessed + # due to assuming role errors. + print("Cannot access adjacent account: ", ACCOUNT_ID, exc) + return None + +session = new_session() +public_access_cidrs = check_cluster(session) +setup_cluster(session, public_access_cidrs) \ No newline at end of file diff --git a/lambda_functions/source/codebuild/setup_images.sh b/lambda_functions/source/codebuild/setup_images.sh new file mode 100644 index 0000000..71a4737 --- /dev/null +++ b/lambda_functions/source/codebuild/setup_images.sh @@ -0,0 +1,36 @@ +#!/bin/bash +echo "Registry is $REGISTRY" +if [ $REGISTRY == "ecr" ]; then + + echo "Getting ECR login..." + aws ecr get-login-password --region $IMAGE_REGION | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com + ecr_uri="$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/crowdstrike" + + echo "Pushing Node Sensor image..." + + node_sensor_repo="crowdstrike/falcon-sensor" + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'falcon-sensor' -c $ecr_uri + echo "export NODE_SENSOR_URI=$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/$node_sensor_repo" >> /root/.bashrc + node_sensor_tag=$(aws ecr list-images --repository-name $node_sensor_repo --query 'imageIds[*].imageTag' --output text) + echo "export NODE_SENSOR_TAG=$node_sensor_tag" >> /root/.bashrc + + echo "Pushing KPA image..." + + kpa_repo="crowdstrike/kpagent" + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'kpagent' -c $ecr_uri + echo "export KPA_URI=$ACCOUNT_ID.dkr.ecr.$IMAGE_REGION.amazonaws.com/$kpa_repo" >> /root/.bashrc + kpa_tag=$(aws ecr list-images --repository-name $kpa_repo --query 'imageIds[*].imageTag' --output text) + echo "export KPA_TAG=$kpa_tag" >> /root/.bashrc + +elif [ $REGISTRY == "crowdstrike" ]; then + + echo "Getting KPA image..." + + curl https://raw.githubusercontent.com/CrowdStrike/falcon-scripts/main/bash/containers/falcon-container-sensor-pull/falcon-container-sensor-pull.sh | bash -s -- -u $FALCON_CLIENT_ID -s $FALCON_CLIENT_SECRET -t 'kpagent' + echo "export KPA_URI=registry.crowdstrike.com/kubernetes_protection/kpagent" >> /root/.bashrc + kpa_tag=$(docker images registry.crowdstrike.com/kubernetes_protection/kpagent --format "{{.Tag}}") + echo "export KPA_TAG=$kpa_tag" >> /root/.bashrc + +else + echo "Missing env variable REGISTRY" +fi \ No newline at end of file diff --git a/lambda_functions/source/codebuild/setup_manifests.sh b/lambda_functions/source/codebuild/setup_manifests.sh new file mode 100644 index 0000000..13e8693 --- /dev/null +++ b/lambda_functions/source/codebuild/setup_manifests.sh @@ -0,0 +1,28 @@ +#!/bin/bash +CID_LOWER=$(echo $CID | cut -d '-' -f 1 | tr '[:upper:]' '[:lower:]') +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" kpa_config.value +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" kpa_config.value +sed -i "s~KPA_URI~$KPA_URI~" kpa_config.value +sed -i "s~KPA_TAG~$KPA_TAG~" kpa_config.value +sed -i "s~CLUSTER_ARN~$CLUSTER_ARN~" kpa_config.value +sed -i "s~CROWDSTRIKE_CLOUD~$CROWDSTRIKE_CLOUD~" kpa_config.value +sed -i "s~CID_LOWER~$CID_LOWER~" kpa_config.value +sed -i "s~DOCKER_API_TOKEN~$DOCKER_API_TOKEN~" kpa_config.value + +if [ $REGISTRY == "ecr" ]; then + sed -i "s~NODE_SENSOR_URI~$NODE_SENSOR_URI~" node_sensor_ecr.yaml + sed -i "s~NODE_SENSOR_TAG~$NODE_SENSOR_TAG~" node_sensor_ecr.yaml + sed -i "s~BACKEND~$BACKEND~" node_sensor_ecr.yaml + sed -i "s~CID~$CID~" node_sensor_ecr.yaml +elif [ $REGISTRY == "crowdstrike" ]; then + sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" node_sensor.yaml + sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" node_sensor.yaml + sed -i "s~BACKEND~$BACKEND~" node_sensor.yaml +fi + +sed -i "s~REGISTRY~$REGISTRY~" sidecar_sensor.yaml +sed -i "s~REGISTRY~$REGISTRY~" falcon_admission.yaml +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" sidecar_sensor.yaml +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" sidecar_sensor.yaml +sed -i "s~FALCON_CLIENT_ID~$FALCON_CLIENT_ID~" falcon_admission.yaml +sed -i "s~FALCON_CLIENT_SECRET~$FALCON_CLIENT_SECRET~" falcon_admission.yaml diff --git a/lambda_functions/source/codebuild/sidecar_sensor.yaml b/lambda_functions/source/codebuild/sidecar_sensor.yaml new file mode 100644 index 0000000..4d9d113 --- /dev/null +++ b/lambda_functions/source/codebuild/sidecar_sensor.yaml @@ -0,0 +1,14 @@ +apiVersion: falcon.crowdstrike.com/v1alpha1 +kind: FalconContainer +metadata: + name: falcon-sidecar-sensor +spec: + falcon_api: + client_id: FALCON_CLIENT_ID + client_secret: FALCON_CLIENT_SECRET + cloud_region: autodiscover + registry: + type: REGISTRY + injector: + disableDefaultNamespaceInjection: true + disableDefaultPodInjection: true \ No newline at end of file diff --git a/lambda_functions/source/cw-helper/organizations.py b/lambda_functions/source/cw-helper/organizations.py index 2f8d143..3779e91 100644 --- a/lambda_functions/source/cw-helper/organizations.py +++ b/lambda_functions/source/cw-helper/organizations.py @@ -15,6 +15,8 @@ LOGGER = logging.getLogger(__name__) log_level: str = os.environ.get("LOG_LEVEL", "ERROR") LOGGER.setLevel(log_level) +EVENTBUS_ACCOUNT = os.environ.get('EVENTBUS_ACCOUNT') +EKS_PROTECTION = os.environ.get('EKS_PROTECTION') def get_org_id(): @@ -26,8 +28,22 @@ def get_org_id(): management_account_session = boto3.Session() org_client = management_account_session.client("organizations") response = org_client.describe_organization()["Organization"] + organization_id = response["Id"] LOGGER.debug({"API_Call": "organizations:DescribeOrganization", "API_Response": response}) - return {"OrganizationId": response["Id"]} + return organization_id + +def get_parents(): + """Get AWS Organization ID. + + Returns: + Response data for custom resource + """ + management_account_session = boto3.Session() + org_client = management_account_session.client("organizations") + response = org_client.list_parents(ChildId=EVENTBUS_ACCOUNT).get('Parents') + eventbus_account_ou = response[0].get('Id') + LOGGER.debug({"API_Call": "organizations:ListParents", "API_Response": response}) + return eventbus_account_ou def lambda_handler(event, context): """Lambda Handler. @@ -37,9 +53,14 @@ def lambda_handler(event, context): context: runtime information """ try: - data = get_org_id() - cfnresponse.send(event, context, cfnresponse.SUCCESS, data, data["OrganizationId"]) + data_dict = {} + organization_id = get_org_id() + data_dict['organization_id'] = organization_id + if EKS_PROTECTION == "true": + eventbus_account_ou = get_parents() + data_dict['eventbus_account_ou'] = eventbus_account_ou + cfnresponse.send(event, context, cfnresponse.SUCCESS, data_dict, data_dict["organization_id"]) except Exception: LOGGER.exception("Unexpected!") reason = f"See the details in CloudWatch Log Stream: '{context.log_group_name}'" - cfnresponse.send(event, context, cfnresponse.FAILED, {}, data["OrganizationId"], reason=reason) + cfnresponse.send(event, context, cfnresponse.FAILED, {}, data_dict, reason=reason) diff --git a/lambda_functions/source/eks-existing-clusters/lambda.py b/lambda_functions/source/eks-existing-clusters/lambda.py new file mode 100644 index 0000000..bc5ca85 --- /dev/null +++ b/lambda_functions/source/eks-existing-clusters/lambda.py @@ -0,0 +1,253 @@ +"""Function running CrowdStrike EKS Protection for existing EKS Clusters.""" +import json +import os +import logging +from datetime import date +import botocore +import boto3 +import requests + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +# CONSTANTS +SUCCESS = "SUCCESS" +FAILED = "FAILED" + +DATE = date.today() +PROJECT = os.environ['project_name'] +BUCKET = os.environ['artifact_bucket'] +REGION = os.environ['AWS_DEFAULT_REGION'] +SWITCH_ROLE = os.environ['lambda_switch_role'] + +def accounts(): + """Function getting AWS Account list.""" + try: + session = boto3.session.Session() + client = session.client( + service_name='organizations', + region_name=REGION + ) + response = client.list_accounts() + response_accounts = response['Accounts'] + next_token = response.get('NextToken', None) + + while next_token: + response = client.list_accounts(NextToken=next_token) + response_accounts += response['Accounts'] + next_token = response.get('NextToken', None) + + active_accounts = [a for a in response_accounts if a['Status'] == 'ACTIVE'] + return active_accounts + except client.exceptions.AccessDeniedException: + print("Cannot autodiscover adjacent accounts: \ + cannot list accounts within the AWS organization") + return None + +def new_session(account_id, region): + """Function establishing boto3 session.""" + try: + sts_connection = boto3.client('sts') + credentials = sts_connection.assume_role( + RoleArn=f'arn:aws:iam::{account_id}:role/{SWITCH_ROLE}', + RoleSessionName=f'crowdstrike-eks-{account_id}' + ) + return boto3.session.Session( + aws_access_key_id=credentials['Credentials']['AccessKeyId'], + aws_secret_access_key=credentials['Credentials']['SecretAccessKey'], + aws_session_token=credentials['Credentials']['SessionToken'], + region_name=region + ) + except sts_connection.exceptions.ClientError as exc: + # Print the error and continue. + # Handle what to do with accounts that cannot be accessed + # due to assuming role errors. + print("Cannot access adjacent account: ", account_id, exc) + return None + + +def regions(): + """Function getting active AWS Regions.""" + session = boto3.session.Session() + client = session.client( + service_name='ec2', + region_name=REGION + ) + + active_regions = client.describe_regions()['Regions'] + return active_regions + + +def clusters(session, region_name): + """Function getting EKS Clusters.""" + client = session.client( + service_name='eks', + region_name=region_name + ) + + response = client.list_clusters(maxResults=100) + eks_clusters = response['clusters'] + next_token = response['NextToken'] if 'NextToken' in response else None + + while next_token: + response = client.list_clusters(maxResults=100, NextToken=next_token) + eks_clusters += response['clusters'] + next_token = response['NextToken'] if 'NextToken' in response else None + + return eks_clusters + +def describe_cluster(session, region_name, cluster_name): + """Function checking EKS Cluster.""" + client = session.client( + service_name='eks', + region_name=region_name + ) + + response = client.describe_cluster(name=cluster_name) + cluster_arn = response.get('cluster', {}).get('arn') + auth_mode = response.get('cluster', {}).get('accessConfig', \ + {}).get('authenticationMode') + public_endpoint = response.get('cluster', {}).get('resourcesVpcConfig', \ + {}).get('endpointPublicAccess') + + return cluster_arn, auth_mode, public_endpoint + +def check_fargate(session, region_name, cluster_name): + """Function checking for Fargate.""" + client = session.client( + service_name='eks', + region_name=region_name + ) + + try: + response = client.list_fargate_profiles( + clusterName=cluster_name, + maxResults=10 + ) + if response['fargateProfileNames'] not in []: + logger.info('No fargate profiles found, setting node_type to nodegroup...') + node_type = 'nodegroup' + else: + node_type = 'fargate' + return node_type + except botocore.exceptions.ClientError as error: + logger.error(error) + return None + +def start_build(cluster_name, cluster_arn, node_type, account_id, region_name): + """Function running CodeBuild for EKS Protection.""" + try: + session = boto3.session.Session() + client = session.client( + service_name='codebuild', + region_name=REGION + ) + build = client.start_build( + projectName=PROJECT, + artifactsOverride={ + 'type': 'S3', + 'location': f'{BUCKET}', + 'path': 'BuildResults', + 'name': f'{cluster_name}-{DATE}', + 'packaging': 'ZIP' + }, + environmentVariablesOverride=[ + { + 'name': 'CLUSTER', + 'value': f'{cluster_name}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'NODE_TYPE', + 'value': f'{node_type}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'CLUSTER_ARN', + 'value': f'{cluster_arn}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'ACCOUNT_ID', + 'value': f'{account_id}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'REGION', + 'value': f'{region_name}', + 'type': 'PLAINTEXT' + } + ] + ) + build_id = build.get('build', {}).get('id') + logger.info('Started build %s, buildId %s' % (PROJECT, build_id)) + except botocore.exceptions.ClientError as error: + logger.error(error) + +def cfnresponse_send(event, response_status, response_data, physical_resource_id=None): + """Function sending response to CloudFormation.""" + response_url = event['ResponseURL'] + print(response_url) + response_body = {} + response_body['Status'] = response_status + response_body['Reason'] = 'See the details in CloudWatch Log Stream: ' + response_body['PhysicalResourceId'] = physical_resource_id + response_body['StackId'] = event['StackId'] + response_body['RequestId'] = event['RequestId'] + response_body['LogicalResourceId'] = event['LogicalResourceId'] + response_body['Data'] = response_data + json_response_body = json.dumps(response_body) + print("Response body:\n" + json_response_body) + headers = { + 'content-type': '', + 'content-length': str(len(json_response_body)) + } + try: + response = requests.put(response_url, + data=json_response_body, + headers=headers, + timeout=5) + print("Status code: " + response.reason) + except Exception as e: + print("send(..) failed executing requests.put(..): " + str(e)) + +def lambda_handler(event, context): + """Function handler.""" + logger.info('Got event %s' % event) + logger.info('Context %s' % context) + logger.info('Gathering Event Details...') + response_d = {} + if event["RequestType"] in ["Create"]: + try: + for account in accounts(): + account_id = account['Id'] + for region in regions(): + region_name = region["RegionName"] + session = new_session(account_id, region_name) + if session: + for cluster_name in clusters(session, region_name): + + cluster_arn, auth_mode, public_endpoint = describe_cluster(session, + region_name, + cluster_name) + if public_endpoint and 'API' in auth_mode: + node_type = check_fargate(session, region_name, cluster_name) + if node_type: + start_build(cluster_name, + cluster_arn, + node_type, + account_id, + region_name) + else: + logger.info('Access denied for cluster %s. \ + Please verify that API Access and Public \ + Endpoint are enabled' % cluster_name) + response_d['status'] = "success" + cfnresponse_send(event, SUCCESS, response_d, "CustomResourcePhysicalID") + except botocore.exceptions.ClientError as error: + logger.error(error) + response_d['error'] = error + cfnresponse_send(event, SUCCESS, response_d, "CustomResourcePhysicalID") + else: + response = {"Status": "Complete"} + cfnresponse_send(event, "SUCCESS", response, "CustomResourcePhysicalID") diff --git a/lambda_functions/source/eks-existing-clusters/requirements.txt b/lambda_functions/source/eks-existing-clusters/requirements.txt new file mode 100644 index 0000000..c3d4b5d --- /dev/null +++ b/lambda_functions/source/eks-existing-clusters/requirements.txt @@ -0,0 +1,2 @@ +urllib3<2 +requests==2.31.0 \ No newline at end of file diff --git a/lambda_functions/source/eks-new-clusters/lambda.py b/lambda_functions/source/eks-new-clusters/lambda.py new file mode 100644 index 0000000..8235735 --- /dev/null +++ b/lambda_functions/source/eks-new-clusters/lambda.py @@ -0,0 +1,121 @@ +"""Function running CrowdStrike EKS Protection for new EKS Clusters.""" +import os +import logging +from datetime import date +import botocore +import boto3 + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +DATE = date.today() +PROJECT = os.environ['project_name'] +BUCKET = os.environ['artifact_bucket'] +SWITCH_ROLE = os.environ['lambda_switch_role'] + +def new_session(account_id, region_name): + """Function establishing boto3 session.""" + try: + sts_connection = boto3.client('sts') + credentials = sts_connection.assume_role( + RoleArn=f'arn:aws:iam::{account_id}:role/{SWITCH_ROLE}', + RoleSessionName=account_id + ) + return boto3.session.Session( + aws_access_key_id=credentials['Credentials']['AccessKeyId'], + aws_secret_access_key=credentials['Credentials']['SecretAccessKey'], + aws_session_token=credentials['Credentials']['SessionToken'], + region_name=region_name + ) + except sts_connection.exceptions.ClientError as exc: + # Print the error and continue. + # Handle what to do with accounts that cannot be accessed + # due to assuming role errors. + print("Cannot access adjacent account: ", account_id, exc) + return None + +def start_build(region, cluster_name, cluster_arn, node_type, account_id, region_name): + """Function running CodeBuild for EKS Protection.""" + try: + session = boto3.session.Session() + client = session.client( + service_name='codebuild', + region_name=region + ) + build = client.start_build( + projectName=PROJECT, + artifactsOverride={ + 'type': 'S3', + 'location': f'{BUCKET}', + 'path': 'BuildResults', + 'name': f'{cluster_name}-{DATE}', + 'packaging': 'ZIP' + }, + environmentVariablesOverride=[ + { + 'name': 'CLUSTER', + 'value': f'{cluster_name}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'NODE_TYPE', + 'value': f'{node_type}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'CLUSTER_ARN', + 'value': f'{cluster_arn}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'ACCOUNT_ID', + 'value': f'{account_id}', + 'type': 'PLAINTEXT' + }, + { + 'name': 'REGION', + 'value': f'{region_name}', + 'type': 'PLAINTEXT' + } + ] + ) + build_id = build.get('build', {}).get('id') + logger.info('Started build %s, buildId %s' % (PROJECT, build_id)) + except botocore.exceptions.ClientError as error: + logger.error(error) + +def lambda_handler(event,context): + """Function handler.""" + logger.info('Got event %s' % event) + logger.info('Context %s' % context) + logger.info('Gathering Event Details...') + region_name = event['region'] + account_id = event['detail']['userIdentity']['accountId'] + cluster_name = event['detail']['requestParameters']['name'] + event_name = event['detail']['eventName'] + if 'CreateCluster' in event_name: + node_type = 'nodegroup' + elif 'CreateFargateProfile' in event_name: + node_type = 'fargate' + else: + node_type = 'nodegroup' + logger.info('Checking EKS Cluster for API Access Config..') + try: + session = new_session(account_id, region_name) + client = session.client( + service_name='eks' + ) + cluster_details = client.describe_cluster( + name=cluster_name + ) + cluster_arn = cluster_details.get('cluster', {}).get('arn') + auth_mode = cluster_details.get('cluster', {}).get('accessConfig',\ + {}).get('authenticationMode') + public_endpoint = cluster_details.get('cluster', {}).get('resourcesVpcConfig',\ + {}).get('endpointPublicAccess') + if public_endpoint and 'API' in auth_mode: + start_build(region_name, cluster_name, cluster_arn, node_type, account_id, region_name) + else: + logger.info('API Access not enabled on cluster %s' % cluster_name) + except botocore.exceptions.ClientError as error: + logger.error(error) diff --git a/lambda_functions/source/register-organization/lambda.py b/lambda_functions/source/register-organization/lambda.py index 4cd0c8d..d7f58fd 100644 --- a/lambda_functions/source/register-organization/lambda.py +++ b/lambda_functions/source/register-organization/lambda.py @@ -1,11 +1,13 @@ +"""Function to register AWS Organization with CrowdStrike""" +# pylint: disable=line-too-long import json import logging import os import sys +import base64 import subprocess import boto3 import requests -import base64 from botocore.exceptions import ClientError # pip install falconpy package to /tmp/ and add to path @@ -21,8 +23,8 @@ FAILED = "FAILED" VERSION = "1.0.0" -name = "crowdstrike-cloud-abi" -useragent = ("%s/%s" % (name, VERSION)) +NAME = "crowdstrike-cloud-abi" +USERAGENT = ("%s/%s" % (NAME, VERSION)) SECRET_STORE_NAME = os.environ['secret_name'] SECRET_STORE_REGION = os.environ['secret_region'] @@ -34,6 +36,7 @@ FALCON_ACCOUNT_TYPE = os.environ['falcon_account_type'] def get_secret(): + """Function to get secret""" session = boto3.session.Session() client = session.client( service_name='secretsmanager', @@ -44,33 +47,25 @@ def get_secret(): SecretId=SECRET_STORE_NAME ) except ClientError as e: - if e.response['Error']['Code'] == 'DecryptionFailureException': - raise e - elif e.response['Error']['Code'] == 'InternalServiceErrorException': - raise e - elif e.response['Error']['Code'] == 'InvalidParameterException': - raise e - elif e.response['Error']['Code'] == 'InvalidRequestException': - raise e - elif e.response['Error']['Code'] == 'ResourceNotFoundException': - raise e + raise e + if 'SecretString' in get_secret_value_response: + secret = get_secret_value_response['SecretString'] else: - if 'SecretString' in get_secret_value_response: - secret = get_secret_value_response['SecretString'] - else: - secret = base64.b64decode(get_secret_value_response['SecretBinary']) - return secret + secret = base64.b64decode(get_secret_value_response['SecretBinary']) + return secret def get_management_id(): - ORG = boto3.client('organizations') + """Function to get Organization Id""" + org = boto3.client('organizations') try: - orgIDstr = ORG.list_roots()['Roots'][0]['Arn'].rsplit('/')[1] - return orgIDstr - except Exception as e: + org_id = org.list_roots()['Roots'][0]['Arn'].rsplit('/')[1] + return org_id + except Exception: logger.error('This stack runs only on the management of the AWS Organization') return False def get_active_regions(): + """Function to get active Regions""" session = boto3.session.Session() client = session.client( service_name='ec2', @@ -119,73 +114,76 @@ def get_active_regions(): return my_regions, comm_gov_eb_regions, ssm_regions except Exception as e: return e - -def cfnresponse_send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False): - responseUrl = event['ResponseURL'] - print(responseUrl) - responseBody = {} - responseBody['Status'] = responseStatus - responseBody['Reason'] = 'See the details in CloudWatch Log Stream: ' - responseBody['PhysicalResourceId'] = physicalResourceId - responseBody['StackId'] = event['StackId'] - responseBody['RequestId'] = event['RequestId'] - responseBody['LogicalResourceId'] = event['LogicalResourceId'] - responseBody['Data'] = responseData - json_responseBody = json.dumps(responseBody) - print("Response body:\n" + json_responseBody) + +def cfnresponse_send(event, response_status, response_data, physical_resource_id=None): + """Function sending response to CloudFormation.""" + response_url = event['ResponseURL'] + print(response_url) + response_body = {} + response_body['Status'] = response_status + response_body['Reason'] = 'See the details in CloudWatch Log Stream: ' + response_body['PhysicalResourceId'] = physical_resource_id + response_body['StackId'] = event['StackId'] + response_body['RequestId'] = event['RequestId'] + response_body['LogicalResourceId'] = event['LogicalResourceId'] + response_body['Data'] = response_data + json_response_body = json.dumps(response_body) + print("Response body:\n" + json_response_body) headers = { 'content-type': '', - 'content-length': str(len(json_responseBody)) + 'content-length': str(len(json_response_body)) } try: - response = requests.put(responseUrl, - data=json_responseBody, - headers=headers) + response = requests.put(response_url, + data=json_response_body, + headers=headers, + timeout=5) print("Status code: " + response.reason) except Exception as e: print("send(..) failed executing requests.put(..): " + str(e)) def lambda_handler(event, context): - logger.info('Got event {}'.format(event)) - logger.info('Context {}'.format(context)) + """Function handler""" + logger.info('Got event %s' % event) + logger.info('Context %s' % context) aws_account_id = context.invoked_function_arn.split(":")[4] regions, comm_gov_eb_regions, ssm_regions = get_active_regions() - OrgId = get_management_id() + org_id = get_management_id() try: secret_str = get_secret() if secret_str: secrets_dict = json.loads(secret_str) - FalconClientId = secrets_dict['FalconClientId'] - FalconSecret = secrets_dict['FalconSecret'] - falcon = CSPMRegistration(client_id=FalconClientId, - client_secret=FalconSecret, + falcon_client_id = secrets_dict['FalconClientId'] + falcon_secret = secrets_dict['FalconSecret'] + falcon = CSPMRegistration(client_id=falcon_client_id, + client_secret=falcon_secret, base_url=CS_CLOUD, - user_agent=useragent + user_agent=USERAGENT ) if event['RequestType'] in ['Create']: - logger.info('Event = {}'.format(event)) + logger.info('Event = %s' % event) if EXISTING_CLOUDTRAIL: response = falcon.create_aws_account(account_id=aws_account_id, - organization_id=OrgId, + organization_id=org_id, behavior_assessment_enabled=True, sensor_management_enabled=True, use_existing_cloudtrail=EXISTING_CLOUDTRAIL, - user_agent=useragent, + user_agent=USERAGENT, is_master=True, account_type=AWS_ACCOUNT_TYPE - ) + ) else: response = falcon.create_aws_account(account_id=aws_account_id, - organization_id=OrgId, + organization_id=org_id, behavior_assessment_enabled=True, sensor_management_enabled=True, use_existing_cloudtrail=EXISTING_CLOUDTRAIL, cloudtrail_region=AWS_REGION, - user_agent=useragent, + user_agent=USERAGENT, is_master=True, account_type=AWS_ACCOUNT_TYPE ) - logger.info('Response: {}'.format(response)) + logger.info('Response: %s' % response) if response['status_code'] == 201: cs_account = response['body']['resources'][0]['intermediate_role_arn'].rsplit('::')[1] response_d = { @@ -210,13 +208,13 @@ def lambda_handler(event, context): response_d['comm_gov_eb_regions'] = comm_gov_eb_regions response_d['my_regions'] = regions response_d['ssm_regions'] = ssm_regions - cfnresponse_send(event, context, SUCCESS, response_d, "CustomResourcePhysicalID") + cfnresponse_send(event, SUCCESS, response_d, "CustomResourcePhysicalID") elif 'already exists' in response['body']['errors'][0]['message']: logger.info(response['body']['errors'][0]['message']) logger.info('Getting existing registration data...') - response = falcon.get_aws_account(organization_ids=OrgId, - user_agent=useragent) - logger.info('Existing Registration Response: {}'.format(response)) + response = falcon.get_aws_account(organization_ids=org_id, + user_agent=USERAGENT) + logger.info('Existing Registration Response: %s' % response) cs_account = response['body']['resources'][0]['intermediate_role_arn'].rsplit('::')[1] response_d = { "cs_account_id": cs_account.rsplit(':')[0], @@ -240,25 +238,25 @@ def lambda_handler(event, context): response_d['comm_gov_eb_regions'] = comm_gov_eb_regions response_d['my_regions'] = regions response_d['ssm_regions'] = ssm_regions - cfnresponse_send(event, context, SUCCESS, response_d, "CustomResourcePhysicalID") + cfnresponse_send(event, SUCCESS, response_d, "CustomResourcePhysicalID") else: error = response['body']['errors'][0]['message'] - logger.info('Account Registration Failed with reason....{}'.format(error)) + logger.info('Account Registration Failed with reason....%s' % error) response_d = { "reason": response['body']['errors'][0]['message'] } - cfnresponse_send(event, context, FAILED, response_d, "CustomResourcePhysicalID") + cfnresponse_send(event, FAILED, response_d, "CustomResourcePhysicalID") elif event['RequestType'] in ['Update']: response_d = {} - logger.info('Event = ' + event['RequestType']) - cfnresponse_send(event, context, SUCCESS, response_d, "CustomResourcePhysicalID") + logger.info('Event = %s' % event['RequestType']) + cfnresponse_send(event, SUCCESS, response_d, "CustomResourcePhysicalID") elif event['RequestType'] in ['Delete']: - logger.info('Event = ' + event['RequestType']) - response = falcon.delete_aws_account(organization_ids=OrgId, - user_agent=useragent + logger.info('Event = %s' % event['RequestType']) + response = falcon.delete_aws_account(organization_ids=org_id, + user_agent=USERAGENT ) - cfnresponse_send(event, context, 'SUCCESS', response['body'], "CustomResourcePhysicalID") + cfnresponse_send(event, 'SUCCESS', response['body'], "CustomResourcePhysicalID") except Exception as err: # noqa: E722 # We can't communicate with the endpoint - logger.info('Registration Failed {}'.format(err)) - cfnresponse_send(event, context, FAILED, err, "CustomResourcePhysicalID") \ No newline at end of file + logger.info('Registration Failed %s' % err) + cfnresponse_send(event, FAILED, err, "CustomResourcePhysicalID") diff --git a/templates/aws_cspm_cloudformation_ioa_comm_gov.json b/templates/aws_cspm_cloudformation_ioa_comm_gov.json index 839550c..a1d1ffd 100644 --- a/templates/aws_cspm_cloudformation_ioa_comm_gov.json +++ b/templates/aws_cspm_cloudformation_ioa_comm_gov.json @@ -311,7 +311,7 @@ }, "S3Key": "aws/aws-lambda-eventbridge.zip" }, - "Description": "", + "Description": "CrowdStrike IOA Lambda", "Environment": { "Variables": { "CS_ADDRESS": "", @@ -417,7 +417,7 @@ }, "S3Key": "aws/aws-lambda-s3.zip" }, - "Description": "", + "Description": "CrowdStrike IOA Lambda", "Environment": { "Variables": { "CS_ADDRESS": "", @@ -518,6 +518,14 @@ "config": { "ignore_checks": ["W3045"] } + }, + "checkov": { + "skip": [ + { + "id": "CKV_AWS_18", + "comment": "S3 access logs intentionally not enabled" + } + ] } }, "Properties": { @@ -795,7 +803,7 @@ }, "S3Key": "aws/aws-lambda-registration.zip" }, - "Description": "", + "Description": "CrowdStrike IOA Lambda", "Timeout": 605, "TracingConfig": { "Mode": "Active" diff --git a/templates/crowdstrike_init_stack.yaml b/templates/crowdstrike_init_stack.yaml index 084c672..dd664e5 100644 --- a/templates/crowdstrike_init_stack.yaml +++ b/templates/crowdstrike_init_stack.yaml @@ -71,6 +71,22 @@ Metadata: - pGovernedRegions - pSecurityAccountId - pLogArchiveAccountId + - Label: + default: EKS Protection + Parameters: + - EKSProtection + - FalconCID + - DockerAPIToken + - EventBusAccount + - EventBusName + - EventBridgeRoleName + - EKSExecutionRoleName + - CodeBuildRoleName + - CodeBuildProjectName + - KubernetesUserName + - Registry + - Backend + - EnableKAC ParameterLabels: # Account Type @@ -161,6 +177,34 @@ Metadata: pLogArchiveAccountId: default: LogArchive Account Id + # EKS Protection + EKSProtection: + default: Enable EKS Protection + FalconCID: + default: Falcon CID + DockerAPIToken: + default: Falcon Docker API Token + EventBusAccount: + default: EKS Protection Account + EventBusName: + default: Name of EventBus + EventBridgeRoleName: + default: Name of EventBridge Role + EKSExecutionRoleName: + default: Name of Execution Role + CodeBuildProjectName: + default: CodeBuild Project Name + CodeBuildRoleName: + default: CodeBuild Role Name + KubernetesUserName: + default: Kubernetes User Name + Registry: + default: Registry + Backend: + default: Backend + EnableKAC: + default: Enable Kubernetes Admission Controller + Parameters: # Account Type FalconAccountType: @@ -368,6 +412,70 @@ Parameters: Description: SRA version to tag Type: String + # EKS Protection + EKSProtection: + Type: String + AllowedValues: ['true', 'false'] + Description: Enable CrowdStrike EKS Protection to automatically deploy Falcon Sensor against EKS Clusters. + Default: 'false' + FalconCID: + Type: String + Description: Your Falcon CID with checksum (eg. ********************************-**) + Default: "FalconCID" + DockerAPIToken: + Type: String + NoEcho: true + Description: Your Falcon Docker API Token + Default: "DockerAPIToken" + EventBusAccount: + Description: The account to centralize EKS Protection resources. This account must be the Organization Management Account or a Delegated Administrator. + Type: String + Default: "111111111111" + EventBusName: + Type: String + Description: Name of the centralized EventBus + Default: crowdstrike-eks-eventbus + EventBridgeRoleName: + Type: String + Description: Name of the EventBridge IAM role + Default: crowdstrike-eks-eventbridge-role + EKSExecutionRoleName: + Type: String + Description: Name of the Target Execution IAM role + Default: crowdstrike-eks-execution-role + CodeBuildProjectName: + Type: String + Description: Name of the CodeBuild Project + Default: crowdstrike-eks-codebuild + CodeBuildRoleName: + Type: String + Description: Name of the CodeBuild IAM role + Default: crowdstrike-eks-codebuild-role + KubernetesUserName: + Type: String + Description: Name of the Kubernetes UserName + Default: crowdstrike-eks + Registry: + Type: String + Description: Source Falcon Image from CrowdStrike or mirror to ECR + AllowedValues: + - 'crowdstrike' + - 'ecr' + Default: crowdstrike + Backend: + Type: String + Description: kernel or bpf for Daemonset Sensor + AllowedValues: + - 'kernel' + - 'bpf' + Default: kernel + EnableKAC: + Type: String + Description: Deploy Kubernetes Admission Controller (KAC). For more info see https://falcon.crowdstrike.com/documentation/page/aa4fccee/container-security#s41cbec3 + AllowedValues: + - true + - false + Default: true Mappings: CloudMap: @@ -395,6 +503,7 @@ Conditions: NotDelegatedAdminCommIOA: !And [ !Equals [ !Ref 'DelegatedAdmin', false ], !Equals [ !Ref 'AWSAccountType', commercial ], !Equals [ !Ref 'FalconAccountType', commercial ], !Equals [!Ref 'EnableIOA', true ]] NotDelegatedAdminGovIOA: !And [ !Equals [ !Ref 'DelegatedAdmin', false ], !Equals [ !Ref 'AWSAccountType', govcloud ], !Equals [ !Ref 'FalconAccountType', govcloud ], !Equals [!Ref 'EnableIOA', true ]] NotDelegatedAdminCommGovIOA: !And [!Equals [ !Ref 'DelegatedAdmin', false ], !Equals [ !Ref 'AWSAccountType', commercial ], !Equals [ !Ref 'FalconAccountType', govcloud ], !Equals [!Ref 'EnableIOA', true ]] + EnableEKSProtection: !Equals [ !Ref 'EKSProtection', true ] Resources: # Optional Default Organization CloudTrail @@ -1085,7 +1194,7 @@ Resources: - !Sub arn:${AWS::Partition}:s3:::${StagingS3Bucket}/* Condition: StringNotEquals: - aws:PrincipalOrgID: !GetAtt OrgIdLambdaCustomResource.OrganizationId + aws:PrincipalOrgID: !GetAtt OrgIdLambdaCustomResource.organization_id - Sid: SecureTransport Effect: Deny @@ -1110,6 +1219,9 @@ Resources: - lambda_functions/packages/register-organization/lambda.zip - lambda_functions/packages/cw-helper/lambda.zip - templates/crowdstrike_init_stack.yaml + - lambda_functions/packages/eks-existing-clusters/lambda.zip + - lambda_functions/packages/eks-new-clusters/lambda.zip + - lambda_functions/packages/codebuild/lambda.zip CopyZipsRole: Type: AWS::IAM::Role @@ -1276,6 +1388,8 @@ Resources: Environment: Variables: LOG_LEVEL: "INFO" + EVENTBUS_ACCOUNT: !Ref EventBusAccount + EKS_PROTECTION: !Ref EKSProtection Code: S3Bucket: !Ref StagingS3Bucket S3Key: !Sub ${SourceS3BucketNamePrefix}/lambda_functions/packages/cw-helper/lambda.zip @@ -1312,7 +1426,9 @@ Resources: Statement: - Sid: OrganizationRead Effect: Allow - Action: organizations:DescribeOrganization + Action: + - organizations:DescribeOrganization + - organizations:ListParents Resource: '*' - PolicyName: CloudWatchLogGroup PolicyDocument: @@ -1326,6 +1442,171 @@ Resources: - logs:PutLogEvents Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${OrgIdLambdaFunctionName}:log-stream:* + # EKS Protection + RootRolesStackSet: + Condition: EnableEKSProtection + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: crowdstrike-eks-protection-root-roles + Capabilities: + - CAPABILITY_NAMED_IAM + AdministrationRoleARN: !GetAtt StackSetAdministrationRole.Arn + ExecutionRoleName: !Ref StackSetExecRole + Parameters: + - ParameterKey: CodeBuildProjectName + ParameterValue: !Ref CodeBuildProjectName + - ParameterKey: CodeBuildRoleName + ParameterValue: !Ref CodeBuildRoleName + - ParameterKey: EventBridgeRoleName + ParameterValue: !Ref EventBridgeRoleName + - ParameterKey: EKSExecutionRoleName + ParameterValue: !Ref EKSExecutionRoleName + - ParameterKey: StagingS3Bucket + ParameterValue: !Ref StagingS3Bucket + - ParameterKey: EventBusName + ParameterValue: !Ref EventBusName + - ParameterKey: PermissionsBoundary + ParameterValue: !Ref PermissionsBoundary + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + AccountFilterType: NONE + Accounts: + - !Ref EventBusAccount + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${SourceS3BucketName}.s3.${S3BucketRegion}.amazonaws.com/${SourceS3BucketNamePrefix}/templates/eks-root-roles.yml + + EKSTargetRolesStackSet: + Condition: EnableEKSProtection + DependsOn: RootRolesStackSet + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: crowdstrike-eks-protection-target-roles + Capabilities: + - CAPABILITY_NAMED_IAM + Parameters: + - ParameterKey: EKSExecutionRoleName + ParameterValue: !Ref EKSExecutionRoleName + - ParameterKey: EventBridgeRoleName + ParameterValue: !Ref EventBridgeRoleName + - ParameterKey: EventBusAccount + ParameterValue: !Ref EventBusAccount + - ParameterKey: EventBusName + ParameterValue: !Ref EventBusName + - ParameterKey: CodeBuildRoleName + ParameterValue: !Ref CodeBuildRoleName + - ParameterKey: PermissionsBoundary + ParameterValue: !Ref PermissionsBoundary + PermissionModel: SERVICE_MANAGED + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: false + OperationPreferences: + MaxConcurrentPercentage: 100 + FailureTolerancePercentage: 50 + RegionConcurrencyType: PARALLEL + StackInstancesGroup: + - DeploymentTargets: + AccountFilterType: NONE + OrganizationalUnitIds: !Ref ProvisionOU + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${SourceS3BucketName}.s3.${S3BucketRegion}.amazonaws.com/${SourceS3BucketNamePrefix}/templates/eks-target-roles-stackset.yml + + RootEKSProtectionStackSet: + Condition: EnableEKSProtection + DependsOn: EKSTargetRolesStackSet + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: crowdstrike-eks-protection-root-protection + Capabilities: + - CAPABILITY_NAMED_IAM + AdministrationRoleARN: !GetAtt StackSetAdministrationRole.Arn + ExecutionRoleName: !Ref StackSetExecRole + Parameters: + - ParameterKey: StagingS3Bucket + ParameterValue: !Ref StagingS3Bucket + - ParameterKey: Backend + ParameterValue: !Ref Backend + - ParameterKey: Registry + ParameterValue: !Ref Registry + - ParameterKey: EnableKAC + ParameterValue: !Ref EnableKAC + - ParameterKey: CrowdStrikeCloud + ParameterValue: !Ref CSCloud + - ParameterKey: EventBusName + ParameterValue: !Ref EventBusName + - ParameterKey: OrganizationId + ParameterValue: !GetAtt OrgIdLambdaCustomResource.organization_id + - ParameterKey: FalconClientId + ParameterValue: !Ref FalconClientID + - ParameterKey: FalconClientSecret + ParameterValue: !Ref FalconSecret + - ParameterKey: KubernetesUserName + ParameterValue: !Ref KubernetesUserName + - ParameterKey: FalconCID + ParameterValue: !Ref FalconCID + - ParameterKey: DockerAPIToken + ParameterValue: !Ref DockerAPIToken + - ParameterKey: EKSExecutionRoleName + ParameterValue: !Ref EKSExecutionRoleName + - ParameterKey: CodeBuildProjectName + ParameterValue: !Ref CodeBuildProjectName + - ParameterKey: CodeBuildRoleName + ParameterValue: !Ref CodeBuildRoleName + - ParameterKey: VpcCIDR + ParameterValue: '10.192.0.0/16' + - ParameterKey: PublicSubnet1CIDR + ParameterValue: '10.192.10.0/24' + - ParameterKey: PublicSubnet2CIDR + ParameterValue: '10.192.11.0/24' + - ParameterKey: PrivateSubnet1CIDR + ParameterValue: '10.192.20.0/24' + - ParameterKey: PrivateSubnet2CIDR + ParameterValue: '10.192.21.0/24' + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + AccountFilterType: NONE + Accounts: + - !Ref EventBusAccount + OrganizationalUnitIds: + - !GetAtt OrgIdLambdaCustomResource.eventbus_account_ou + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${SourceS3BucketName}.s3.${S3BucketRegion}.amazonaws.com/${SourceS3BucketNamePrefix}/templates/eks-protection-stack.yml + + EKSEventBridgeStackSet: + Condition: EnableEKSProtection + DependsOn: RootEKSProtectionStackSet + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: crowdstrike-eks-protection-eventbridge + Parameters: + - ParameterKey: EventBusName + ParameterValue: !Ref EventBusName + - ParameterKey: EventBusAccount + ParameterValue: !Ref EventBusAccount + - ParameterKey: EventBusRegion + ParameterValue: !Ref AWS::Region + - ParameterKey: EventBridgeRoleName + ParameterValue: !Ref EventBridgeRoleName + PermissionModel: SERVICE_MANAGED + AutoDeployment: + Enabled: true + RetainStacksOnAccountRemoval: true + OperationPreferences: + MaxConcurrentPercentage: 100 + FailureTolerancePercentage: 50 + RegionConcurrencyType: PARALLEL + StackInstancesGroup: + - DeploymentTargets: + AccountFilterType: NONE + OrganizationalUnitIds: !Ref ProvisionOU + Regions: !GetAtt TriggerRegisterAccountLambda.my_regions + TemplateURL: !Sub https://${SourceS3BucketName}.s3.${S3BucketRegion}.amazonaws.com/${SourceS3BucketNamePrefix}/templates/eks-eventbridge-stackset.yml + Outputs: CSBucket: Condition: CreateIOATrail diff --git a/templates/eks-eventbridge-stackset.yml b/templates/eks-eventbridge-stackset.yml new file mode 100644 index 0000000..12f63a4 --- /dev/null +++ b/templates/eks-eventbridge-stackset.yml @@ -0,0 +1,35 @@ +--- +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + EventBusRegion: + Type: String + EventBusAccount: + Type: String + EventBusName: + Type: String + EventBridgeRoleName: + Type: String + +Resources: + EKSRule: + Type: AWS::Events::Rule + Properties: + Description: "Invoke CrowdStrike EKS Lambda when clusters or Fargate profiles are created." + EventPattern: + source: + - "aws.eks" + detail-type: + - "AWS API Call via CloudTrail" + detail: + eventSource: + - "eks.amazonaws.com" + eventName: + - "CreateCluster" + - "CreateFargateProfile" + State: "ENABLED" + Name: crowdstrike-eks-rule + Targets: + - Arn: !Sub arn:${AWS::Partition}:events:${EventBusRegion}:${EventBusAccount}:event-bus/${EventBusName} + Id: "CrowdStrikeEKSEventBus" + RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${EventBridgeRoleName} diff --git a/templates/eks-protection-stack.yml b/templates/eks-protection-stack.yml new file mode 100644 index 0000000..ee348b7 --- /dev/null +++ b/templates/eks-protection-stack.yml @@ -0,0 +1,543 @@ +--- +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + StagingS3Bucket: + Type: String + Backend: + Type: String + Description: kernel or bpf for Daemonset Sensor + AllowedValues: + - 'kernel' + - 'bpf' + Default: 'kernel' + Registry: + Type: String + Description: Source Falcon Image from CrowdStrike or mirror to ECR + AllowedValues: + - 'crowdstrike' + - 'ecr' + Default: 'crowdstrike' + EnableKAC: + Type: String + Description: Deploy Kubernetes Admission Controller (KAC). For more info see https://falcon.crowdstrike.com/documentation/page/aa4fccee/container-security#s41cbec3 + AllowedValues: + - 'true' + - 'false' + Default: 'true' + CrowdStrikeCloud: + Type: String + Description: Cloud for your Falcon CID (eg. us-1, us-2 or eu-1) + AllowedValues: + - 'us-1' + - 'us-2' + - 'eu-1' + Default: 'us-1' + EventBusName: + Type: String + Default: "crowdstrike-eks-eventbus" + OrganizationId: + Type: String + FalconClientId: + Type: String + NoEcho: true + FalconClientSecret: + Type: String + NoEcho: true + KubernetesUserName: + Type: String + Default: crowdstrike-eks + FalconCID: + Type: String + DockerAPIToken: + Type: String + NoEcho: true + EKSExecutionRoleName: + Type: String + Default: crowdstrike-eks-execution-role + CodeBuildProjectName: + Type: String + Default: crowdstrike-eks-codebuild + CodeBuildRoleName: + Type: String + Default: crowdstrike-eks-codebuild-role + EnvironmentName: + Description: An environment name that is prefixed to resource names + Type: String + Default: crowdstrike-eks + VpcCIDR: + Description: Please enter the IP range (CIDR notation) for this VPC + Type: String + Default: 10.192.0.0/16 + PublicSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone + Type: String + Default: 10.192.10.0/24 + PublicSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone + Type: String + Default: 10.192.11.0/24 + PrivateSubnet1CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone + Type: String + Default: 10.192.20.0/24 + PrivateSubnet2CIDR: + Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone + Type: String + Default: 10.192.21.0/24 + SourceS3BucketNamePrefix: + Description: + Staging S3 bucket name prefix for the artifacts relevant to the solutions. (e.g., lambda zips, CloudFormation templates). The account + and region are added to the prefix --. Example = staging-123456789012-us-east-1. + Type: String + +Conditions: + UseECR: !Equals [ !Ref 'Registry', 'ecr' ] + +Resources: + # EventBridge Resources to Invoke Lambda + EKSEventBus: + Type: AWS::Events::EventBus + Properties: + Name: !Ref EventBusName + Policy: !Sub | + { + "Version": "2012-10-17", + "Statement": [{ + "Sid": "AllowAllAccountsFromOrganizationToPutEvents", + "Effect": "Allow", + "Principal": "*", + "Action": "events:PutEvents", + "Resource": "arn:aws:events:${AWS::Region}:${AWS::AccountId}:event-bus/${EventBusName}", + "Condition": { + "StringEquals": { + "aws:PrincipalOrgID": "${OrganizationId}" + } + } + }] + } + EKSRule: + Type: AWS::Events::Rule + Properties: + Description: "EventRule" + EventBusName: !GetAtt EKSEventBus.Arn + EventPattern: + source: + - "aws.eks" + detail-type: + - "AWS API Call via CloudTrail" + detail: + eventSource: + - "eks.amazonaws.com" + eventName: + - "CreateCluster" + - "CreateFargateProfile" + State: "ENABLED" + Name: crowdstrike-eks-rule + Targets: + - Arn: !GetAtt EKSLambda.Arn + Id: "CrowdStrikeEKSFunction" + + # Lambda Function to process event, check for EKS API Access and StartBuild + EKSLambda: + Type: AWS::Lambda::Function + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: Lambda custom resource only run during stack lifecycle events. + - id: W92 + reason: Lambda custom resource only run during stack lifecycle events. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + Environment: + Variables: + project_name: !Ref CodeBuildProjectName + artifact_bucket: !Ref StagingS3Bucket + lambda_switch_role: !Ref EKSExecutionRoleName + Handler: lambda_function.lambda_handler + MemorySize: 128 + Role: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${EKSExecutionRoleName} + Runtime: python3.11 + Timeout: 300 + FunctionName: crowdstrike-abi-eks-events-function + Code: + S3Bucket: !Ref StagingS3Bucket + S3Key: !Sub ${SourceS3BucketNamePrefix}/lambda_functions/packages/eks-new-clusters/lambda.zip + EKSInvokeLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref EKSLambda + Action: "lambda:InvokeFunction" + Principal: "events.amazonaws.com" + SourceArn: !GetAtt EKSRule.Arn + ExistingEKSLambda: + Type: AWS::Lambda::Function + Metadata: + cfn_nag: + rules_to_suppress: + - id: W89 + reason: Lambda custom resource only run during stack lifecycle events. + - id: W92 + reason: Lambda custom resource only run during stack lifecycle events. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Properties: + Environment: + Variables: + project_name: !Ref CodeBuildProjectName + artifact_bucket: !Ref StagingS3Bucket + lambda_switch_role: !Ref EKSExecutionRoleName + Handler: lambda_function.lambda_handler + MemorySize: 128 + Role: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${EKSExecutionRoleName} + Runtime: python3.11 + Timeout: 300 + FunctionName: crowdstrike-abi-eks-init-function + Code: + S3Bucket: !Ref StagingS3Bucket + S3Key: !Sub ${SourceS3BucketNamePrefix}/lambda_functions/packages/eks-existing-clusters/lambda.zip + # Trigger Lambda Function + TriggerExistingEKSLambda: + Type: 'Custom::TriggerLambda' + DependsOn: + - SMFalconAPIKey + Properties: + ServiceToken: !GetAtt + - ExistingEKSLambda + - Arn + + # CodeBuild Project to deploy Falcon Operator and Sensor + EKSCodeBuild: + Type: AWS::CodeBuild::Project + Properties: + Description: "Triggered by CrowdStrike EKS Lambda to provision Falcon Operator and Sensor" + Environment: + ComputeType: BUILD_GENERAL1_SMALL + EnvironmentVariables: + - Name: FALCON_CLIENT_ID + Value: !Sub + - '${arn}:client_id' + - { arn: !Ref SMFalconAPIKey } + Type: SECRETS_MANAGER + - Name: FALCON_CLIENT_SECRET + Value: !Sub + - '${arn}:client_secret' + - { arn: !Ref SMFalconAPIKey } + Type: SECRETS_MANAGER + - Name: CS_CLOUD + Value: !Sub + - '${arn}:cs_cloud' + - { arn: !Ref SMFalconAPIKey } + Type: SECRETS_MANAGER + - Name: DOCKER_API_TOKEN + Value: !Sub + - '${arn}:docker_api_token' + - { arn: !Ref SMFalconAPIKey } + Type: SECRETS_MANAGER + - Name: PRINCIPAL_ARN + Type: PLAINTEXT + Value: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${CodeBuildRoleName} + - Name: S3_BUCKET + Type: PLAINTEXT + Value: !Ref StagingS3Bucket + - Name: USERNAME + Type: PLAINTEXT + Value: !Ref KubernetesUserName + - Name: CLUSTER + Type: PLAINTEXT + Value: lambda + - Name: CLUSTER_ARN + Type: PLAINTEXT + Value: lambda + - Name: NODE_TYPE + Type: PLAINTEXT + Value: lambda + - Name: CID + Type: PLAINTEXT + Value: !Ref FalconCID + - Name: ENABLE_KAC + Type: PLAINTEXT + Value: !Ref EnableKAC + - Name: REGISTRY + Type: PLAINTEXT + Value: !Ref Registry + - Name: CROWDSTRIKE_CLOUD + Type: PLAINTEXT + Value: !Ref CrowdStrikeCloud + - Name: BACKEND + Type: PLAINTEXT + Value: !Ref Backend + - Name: IMAGE_REGION + Type: PLAINTEXT + Value: !If [ UseECR, !Ref AWS::Region, 'CrowdStrike' ] + - Name: NODE_SENSOR_REPO + Type: PLAINTEXT + Value: !If [ UseECR, !Ref NodeSensorRepo, 'CrowdStrike' ] + - Name: NODE_SENSOR_URI + Type: PLAINTEXT + Value: !If [ UseECR, !GetAtt NodeSensorRepo.RepositoryUri, 'CrowdStrike' ] + - Name: ACCOUNT_ID + Type: PLAINTEXT + Value: lambda + - Name: REGION + Type: PLAINTEXT + Value: lambda + - Name: SWITCH_ROLE + Type: PLAINTEXT + Value: !Ref EKSExecutionRoleName + - Name: NAT_IP + Type: PLAINTEXT + Value: !GetAtt NatGatewayEIP.PublicIp + Image: aws/codebuild/standard:7.0 + PrivilegedMode: true + Type: LINUX_CONTAINER + VpcConfig: + SecurityGroupIds: + - !GetAtt NoIngressSecurityGroup.GroupId + Subnets: + - !GetAtt PrivateSubnet1.SubnetId + VpcId: !GetAtt PrivateSubnet1.VpcId + Artifacts: + Type: NO_ARTIFACTS + Name: !Ref CodeBuildProjectName + ServiceRole: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${CodeBuildRoleName} + Source: + Location: !Sub '${StagingS3Bucket}/${SourceS3BucketNamePrefix}/lambda_functions/packages/codebuild/lambda.zip' + Type: S3 + TimeoutInMinutes: 90 + Visibility: PRIVATE + +# Secret + SMFalconAPIKey: + Type: AWS::SecretsManager::Secret + Metadata: + checkov: + skip: + - id: CKV_AWS_149 + comment: The default key aws/secretsmanager is sufficient to secure this resource + Properties: + Name: crowdstrike-eks-secret + Description: 'Client ID and Secret for the Falcon API' + SecretString: !Sub | + { + "client_id": "${FalconClientId}", + "client_secret": "${FalconClientSecret}", + "cid": "${FalconCID}", + "cs_cloud":"${CrowdStrikeCloud}", + "docker_api_token":"${DockerAPIToken}" + } + + # Create ECR Repositories for Falcon Images + NodeSensorRepo: + Type: AWS::ECR::Repository + Condition: UseECR + Properties: + ImageScanningConfiguration: + ScanOnPush: true + EmptyOnDelete: true + RepositoryName: crowdstrike/falcon-sensor + RepositoryPolicyText: + Version: "2012-10-17" + Statement: + - + Sid: AllowPushPull + Effect: Allow + Principal: + AWS: + - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${CodeBuildRoleName} + Action: + - "ecr:GetDownloadUrlForLayer" + - "ecr:BatchGetImage" + - "ecr:BatchCheckLayerAvailability" + - "ecr:PutImage" + - "ecr:InitiateLayerUpload" + - "ecr:UploadLayerPart" + - "ecr:CompleteLayerUpload" + KPAgentRepo: + Type: AWS::ECR::Repository + Condition: UseECR + Properties: + ImageScanningConfiguration: + ScanOnPush: true + EmptyOnDelete: true + RepositoryName: crowdstrike/kpagent + RepositoryPolicyText: + Version: "2012-10-17" + Statement: + - + Sid: AllowPushPull + Effect: Allow + Principal: + AWS: + - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${CodeBuildRoleName} + Action: + - "ecr:GetDownloadUrlForLayer" + - "ecr:BatchGetImage" + - "ecr:BatchCheckLayerAvailability" + - "ecr:PutImage" + - "ecr:InitiateLayerUpload" + - "ecr:UploadLayerPart" + - "ecr:CompleteLayerUpload" + + # Network + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsSupport: true + EnableDnsHostnames: true + Tags: + - Key: Name + Value: !Ref EnvironmentName + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Ref EnvironmentName + + InternetGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref InternetGateway + VpcId: !Ref VPC + + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet1CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Public Subnet (AZ1) + + PublicSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PublicSubnet2CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Public Subnet (AZ2) + + PrivateSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 0, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet1CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Private Subnet (AZ1) + + PrivateSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + AvailabilityZone: !Select [ 1, !GetAZs '' ] + CidrBlock: !Ref PrivateSubnet2CIDR + MapPublicIpOnLaunch: false + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Private Subnet (AZ2) + + NatGatewayEIP: + Type: AWS::EC2::EIP + DependsOn: InternetGatewayAttachment + Properties: + Domain: vpc + + NatGateway: + Type: AWS::EC2::NatGateway + Properties: + AllocationId: !GetAtt NatGatewayEIP.AllocationId + SubnetId: !Ref PublicSubnet1 + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Public Routes + + DefaultPublicRoute: + Type: AWS::EC2::Route + DependsOn: InternetGatewayAttachment + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PublicSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet1 + + PublicSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnet2 + + PrivateRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${EnvironmentName} Private Routes (AZ1) + + DefaultPrivateRoute: + Type: AWS::EC2::Route + Properties: + RouteTableId: !Ref PrivateRouteTable + DestinationCidrBlock: 0.0.0.0/0 + NatGatewayId: !Ref NatGateway + + PrivateSubnet1RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable + SubnetId: !Ref PrivateSubnet1 + + PrivateSubnet2RouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PrivateRouteTable + SubnetId: !Ref PrivateSubnet2 + + NoIngressSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: "Security group with no ingress rule" + VpcId: !Ref VPC + SecurityGroupEgress: + - IpProtocol: -1 + CidrIp: 0.0.0.0/0 + Description: "Allow all egress" \ No newline at end of file diff --git a/templates/eks-root-roles.yml b/templates/eks-root-roles.yml new file mode 100644 index 0000000..d8b2f7c --- /dev/null +++ b/templates/eks-root-roles.yml @@ -0,0 +1,237 @@ +--- +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + CodeBuildProjectName: + Type: String + Default: "crowdstrike-eks-codebuild" + CodeBuildRoleName: + Type: String + Default: "crowdstrike-eks-codebuild-role" + EventBridgeRoleName: + Type: String + Default: "crowdstrike-eks-eventbridge-role" + EKSExecutionRoleName: + Type: String + Default: "crowdstrike-eks-execution-role" + StagingS3Bucket: + Type: String + EventBusName: + Type: String + Default: "crowdstrike-eks-eventbus" + PermissionsBoundary: + Type: String + Description: The name of the policy used to set the permissions boundary for IAM roles. + Default: '' + +Conditions: + SetPermissionsBoundary: !Not [ !Equals [ !Ref PermissionsBoundary, '' ] ] + +Resources: + EKSEventBridgeRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Ref EventBridgeRoleName + PermissionsBoundary: + Fn::If: + - SetPermissionsBoundary + - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${PermissionsBoundary}' + - Ref: AWS::NoValue + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: events.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: crowdstrike-eks-eb-role + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: events:PutEvents + Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/${EventBusName} + + EKSExecutionRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: !Ref EKSExecutionRoleName + PermissionsBoundary: + Fn::If: + - SetPermissionsBoundary + - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${PermissionsBoundary}' + - Ref: AWS::NoValue + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - 'sts:AssumeRole' + ManagedPolicyArns: + - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' + Policies: + - PolicyName: crowdstrike-eks-execution-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - organizations:ListAccounts + Resource: '*' + - Effect: Allow + Action: + - ec2:DescribeRegions + Resource: '*' + - Effect: Allow + Action: + - codebuild:StartBuild + Resource: + - !Sub 'arn:${AWS::Partition}:codebuild:*:${AWS::AccountId}:project/${CodeBuildProjectName}' + - Effect: Allow + Action: + - sts:AssumeRole + Resource: + - !Sub arn:${AWS::Partition}:iam::*:role/${EKSExecutionRoleName} + + EKSCodeBuildRole: + Type: 'AWS::IAM::Role' + Metadata: + cfn-lint: + config: + ignore_checks: + - EIAMPolicyWildcardResource # Role has * to allow for future service monitoring without stack updates + - EIAMPolicyActionWildcard # Role has * to allow for future service monitoring without stack updates + checkov: + skip: + - id: CKV_AWS_109 + comment: IAM PassRole action is constrained by resource ARN. + - id: CKV_AWS_111 + comment: IAM PassRole action is constrained by resource ARN. + Properties: + RoleName: !Ref CodeBuildRoleName + PermissionsBoundary: + Fn::If: + - SetPermissionsBoundary + - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${PermissionsBoundary}' + - Ref: AWS::NoValue + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - codebuild.amazonaws.com + Action: + - 'sts:AssumeRole' + Policies: + - PolicyName: codebuild-base-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${CodeBuildProjectName}' + - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${CodeBuildProjectName}:*' + - Effect: Allow + Action: + - s3:PutObject + - s3:GetObject + - s3:GetObjectVersion + - s3:GetBucketAcl + - s3:GetBucketLocation + Resource: + - !Sub 'arn:${AWS::Partition}:s3:::codepipeline-${AWS::Region}-*' + - Effect: Allow + Action: + - codebuild:CreateReportGroup + - codebuild:CreateReport + - codebuild:UpdateReport + - codebuild:BatchPutTestCases + - codebuild:BatchPutCodeCoverages + Resource: + - !Sub 'arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/${CodeBuildProjectName}-*' + - PolicyName: codebuild-s3-readonly-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - s3:GetObject + - s3:GetObjectVersion + Resource: + - !Sub 'arn:${AWS::Partition}:s3:::${StagingS3Bucket}/buildspec.yml' + - !Sub 'arn:${AWS::Partition}:s3:::${StagingS3Bucket}/*' + - Effect: Allow + Action: + - s3:ListBucket + - s3:GetBucketAcl + - s3:GetBucketLocation + Resource: + - !Sub 'arn:${AWS::Partition}:s3:::${StagingS3Bucket}' + - PolicyName: codebuild-eks-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - eks:DescribeFargateProfile + - eks:ListAccessEntries + - eks:ListAssociatedAccessPolicies + - eks:DescribeNodegroup + - eks:ListIdentityProviderConfigs + - eks:ListNodegroups + - eks:DescribeAccessEntry + - eks:ListFargateProfiles + - eks:DescribeIdentityProviderConfig + - eks:DescribeUpdate + - eks:AccessKubernetesApi + - eks:DescribeCluster + - eks:ListClusters + - eks:ListAccessPolicies + - eks:AssociateIdentityProviderConfig + - eks:AssociateAccessPolicy + - eks:DisassociateAccessPolicy + - ecr:GetAuthorizationToken + - ecr:ListImages + - ecr:InitiateLayerUpload + - ecr:CreateRepository + - ecr:CompleteLayerUpload + - ecr:PutImage + - iam:CreateOpenIDConnectProvider + - iam:GetOpenIDConnectProvider + - ec2:CreateNetworkInterface + - ec2:CreateNetworkInterfacePermission + - ec2:DeleteNetworkInterface + - ec2:DescribeDhcpOptions + - ec2:DescribeNetworkInterfaces + - ec2:DeleteNetworkInterface + - ec2:DescribeSubnets + - ec2:DescribeSecurityGroups + - ec2:DescribeVpcs + Resource: '*' + - Effect: Allow + Action: + - eks:UpdateAccessEntry + - eks:CreateAccessEntry + - eks:DeleteAccessEntry + Resource: + - !Sub 'arn:${AWS::Partition}:eks:*:*:cluster/*' + - !Sub 'arn:${AWS::Partition}:eks:*:*:access-entry/*/${CodeBuildRoleName}/${AWS::AccountId}/$/*' + - Effect: Allow + Action: + - secretsmanager:GetSecretValue + Resource: + - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:crowdstrike-eks-secret-*' + - Effect: Allow + Action: + - sts:AssumeRole + Resource: + - !Sub arn:${AWS::Partition}:iam::*:role/${EKSExecutionRoleName} diff --git a/templates/eks-target-roles-stackset.yml b/templates/eks-target-roles-stackset.yml new file mode 100644 index 0000000..d7ab1b7 --- /dev/null +++ b/templates/eks-target-roles-stackset.yml @@ -0,0 +1,113 @@ +--- +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + EKSExecutionRoleName: + Type: String + Default: "crowdstrike-eks-execution-role" + EventBridgeRoleName: + Type: String + Default: "crowdstrike-eks-eventbridge-role" + EventBusAccount: + Type: String + EventBusName: + Type: String + Default: "crowdstrike-eks-eventbus" + CodeBuildRoleName: + Type: String + Default: "crowdstrike-eks-codebuild-role" + PermissionsBoundary: + Type: String + Description: The name of the policy used to set the permissions boundary for IAM roles. + Default: '' + +Conditions: + SetPermissionsBoundary: !Not [ !Equals [ !Ref PermissionsBoundary, '' ] ] + +Resources: + EventBridgeRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: !Ref EventBridgeRoleName + PermissionsBoundary: + Fn::If: + - SetPermissionsBoundary + - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${PermissionsBoundary}' + - Ref: AWS::NoValue + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - events.amazonaws.com + Action: + - 'sts:AssumeRole' + Policies: + - PolicyName: crowdstrike-eks-eventbridge-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - events:PutEvents + Resource: + - !Sub arn:${AWS::Partition}:events:${AWS::Region}:${EventBusAccount}:event-bus/${EventBusName} + + EKSExecutionRole: + Type: 'AWS::IAM::Role' + Metadata: + cfn-lint: + config: + ignore_checks: + - EIAMPolicyWildcardResource # Role has * to allow for future service monitoring without stack updates + - EIAMPolicyActionWildcard # Role has * to allow for future service monitoring without stack updates + checkov: + skip: + - id: CKV_AWS_111 + comment: constraints must be suppressed due to resource arns only known at execution + Properties: + RoleName: !Ref EKSExecutionRoleName + PermissionsBoundary: + Fn::If: + - SetPermissionsBoundary + - !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${PermissionsBoundary}' + - Ref: AWS::NoValue + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + AWS: + - !Sub arn:${AWS::Partition}:iam::${EventBusAccount}:role/${EKSExecutionRoleName} + - !Sub arn:${AWS::Partition}:sts::${EventBusAccount}:role/${CodeBuildRoleName} + Action: + - 'sts:AssumeRole' + Policies: + - PolicyName: crowdstrike-eks-execution-policy + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Action: + - eks:DescribeCluster + - eks:ListClusters + - eks:ListFargateProfiles + - ec2:DescribeRegions + - eks:UpdateClusterConfig + - eks:DescribeUpdate + - eks:AssociateAccessPolicy + Resource: '*' + - Effect: Allow + Action: + - ec2:DescribeRegions + Resource: '*' + - Effect: Allow + Action: + - eks:UpdateAccessEntry + - eks:CreateAccessEntry + - eks:DeleteAccessEntry + - eks:DescribeAccessEntry + Resource: + - !Sub 'arn:${AWS::Partition}:eks:*:${AWS::AccountId}:cluster/*' + - !Sub 'arn:${AWS::Partition}:eks:*:${AWS::AccountId}:access-entry/*/${CodeBuildRoleName}/${EventBusAccount}/$/*'