diff --git a/README.md b/README.md index 8651234c..e803e4dd 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,7 @@ Patterns: snyk starter gmaestro + workloads-codecommit ``` - Bootstrap your CDK environment. diff --git a/bin/workloads-codecommit.ts b/bin/workloads-codecommit.ts new file mode 100644 index 00000000..2c853529 --- /dev/null +++ b/bin/workloads-codecommit.ts @@ -0,0 +1,6 @@ +import WorkloadsCodeCommitConstruct from '../lib/workloads-codecommit-construct'; +import { configureApp } from '../lib/common/construct-utils'; + +const app = configureApp(); + +new WorkloadsCodeCommitConstruct(app, 'workloads-codecommit'); diff --git a/docs/patterns/images/argocd-cc-workloads.png b/docs/patterns/images/argocd-cc-workloads.png new file mode 100644 index 00000000..ba4f8024 Binary files /dev/null and b/docs/patterns/images/argocd-cc-workloads.png differ diff --git a/docs/patterns/images/argocd-cc.png b/docs/patterns/images/argocd-cc.png new file mode 100644 index 00000000..2da385ad Binary files /dev/null and b/docs/patterns/images/argocd-cc.png differ diff --git a/docs/patterns/workloads-codecommit.md b/docs/patterns/workloads-codecommit.md new file mode 100644 index 00000000..3fd87b50 --- /dev/null +++ b/docs/patterns/workloads-codecommit.md @@ -0,0 +1,189 @@ +# EKS Cluster with ArgoCD and Workloads in private AWS CodeCommit repository + +## Objective + +This example shows how to provision an EKS cluster with: + +- ArgoCD +- Workloads deployed by ArgoCD +- Private AWS CodeCommit repository to store the configurations of workloads +- Setup to trigger ArgoCD projects sync on git push to AWS CodeCommit repository + +Pattern source: /lib/workloads-codecommit-construct/index.ts + +## Architecture + +![Architectural diagram](./images/argocd-cc.png) + +To better understand how ArgoCD works with EKS Blueprints, read the EKS Blueprints ArgoCD [Documentation](https://aws-quickstart.github.io/cdk-eks-blueprints/addons/argo-cd/) + +- After a push to AWS CodeCommit repository notification trigger calls AWS Lambda +- AWS Lambda calls ArgoCD webhook URL to trigger ArgoCD projects sync + +## Prerequisites + +Ensure that you have installed the following tools on your machine. + +1. [aws cli](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) +2. [kubectl](https://Kubernetes.io/docs/tasks/tools/) +3. [cdk](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_install) +4. [npm](https://docs.npmjs.com/cli/v8/commands/npm-install) +5. [jq](https://jqlang.github.io/jq/) +6. `make` + +## Deploy EKS Cluster with Amazon EKS Blueprints for CDK + +1. Clone the repository + +```sh +git clone https://github.com/aws-samples/cdk-eks-blueprints-patterns.git +cd cdk-eks-blueprints-patterns +``` + +2. Update npm + +```sh +npm install -g npm@latest +``` + +3. View patterns and deploy workloads-codecommit pattern + +```sh +make list +npx cdk bootstrap +make pattern workloads-codecommit deploy +``` + +## Verify the resources + +1. Run the update-kubeconfig command. You should be able to get the command from the CDK output message. More information can be found at https://aws-quickstart.github.io/cdk-eks-blueprints/getting-started/#cluster-access + +```sh +aws eks update-kubeconfig --name workloads-codecommit-blueprint --region --role-arn arn:aws:iam::xxxxxxxxx:role/workloads-codecommit-blue-workloadscodecommitbluepr-VH6YOKWPAt5H +``` + +2. Verify the resources created from the steps above. + +```bash +$ kubectl get po -n argocd +NAME READY STATUS RESTARTS AGE +blueprints-addon-argocd-application-controller-0 1/1 Running 0 1h +blueprints-addon-argocd-applicationset-controller-7b78c7fc5dmkx 1/1 Running 0 1h +blueprints-addon-argocd-dex-server-6cf94ddc54-p68pl 1/1 Running 0 1h +blueprints-addon-argocd-notifications-controller-6f6b7d95ckhf6p 1/1 Running 0 1h +blueprints-addon-argocd-redis-b8dbc7dc6-dvbkr 1/1 Running 0 1h +blueprints-addon-argocd-repo-server-66df7f448f-kvwmw 1/1 Running 0 1h +blueprints-addon-argocd-server-584db5f545-8xp48 1/1 Running 0 1h +``` + +## Give ArgoCD access to AWS CodeCommit + +```bash +until kubectl get svc blueprints-addon-argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname' | grep -m 1 "elb.amazonaws.com"; do sleep 5 ; done; +export ARGOCD_SERVER=`kubectl get svc blueprints-addon-argocd-server -n argocd -o json | jq --raw-output '.status.loadBalancer.ingress[0].hostname'` + +export ARGOCD_USER=argocd-cc +export CC_REPO_NAME=eks-blueprints-workloads-cc + +aws iam create-service-specific-credential --user-name $ARGOCD_USER --service-name codecommit.amazonaws.com --no-cli-pager +export CC_REPO_URL=$(aws codecommit get-repository --repository-name $CC_REPO_NAME --query 'repositoryMetadata.cloneUrlHttp' --output text) +export SSC_ID=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[0].ServiceSpecificCredentialId' --output text) +export SSC_USER=$(aws iam list-service-specific-credentials --user-name $ARGOCD_USER --query 'ServiceSpecificCredentials[0].ServiceUserName' --output text) +export SSC_PWD=$(aws iam reset-service-specific-credential --user-name $ARGOCD_USER --service-specific-credential-id $SSC_ID --query 'ServiceSpecificCredential.ServicePassword' --output text) + +cat > argocd-workloads-repos-creds.yaml < trigger.json < = [ + new blueprints.NestedStackAddOn({ + builder: WorkloadsCodeCommitRepoStack.builder(userName, repoName), + id: repoName + "-codecommit-repo-nested-stack" + }), + new blueprints.SecretsStoreAddOn, + new blueprints.ArgoCDAddOn({ + bootstrapRepo: { + ...bootstrapRepo, + path: 'envs/dev', + }, + values: { + server: { + service: { + type: "LoadBalancer" + } + } + } + }) + ]; + + blueprints.EksBlueprint.builder() + .account(process.env.CDK_DEFAULT_ACCOUNT!) + .region(process.env.CDK_DEFAULT_REGION) + .addOns(...addOns) + + .version('auto') + .build(scope, stackId); + } +} diff --git a/lib/workloads-codecommit-construct/lambda/index.js b/lib/workloads-codecommit-construct/lambda/index.js new file mode 100644 index 00000000..7429be98 --- /dev/null +++ b/lib/workloads-codecommit-construct/lambda/index.js @@ -0,0 +1,52 @@ +/* eslint-env node */ +const https = require('https'); // eslint-disable-line + +/* webhook payload + { + "ref": "refs/heads/main", + "repository": { + "html_url": "https://git-codecommit.us-west-2.amazonaws.com/v1/repos/eks-blueprints-workloads-cc", + "default_branch": "main" + } + } +*/ + +exports.handler = async function(event) { + const eventSourceARNarray = event.Records[0].eventSourceARN.split(':'); + const repoName = eventSourceARNarray[eventSourceARNarray.length - 1]; + const ref = event.Records[0].codecommit.references[0].ref; + const refArray = ref.split('/'); + const branch = refArray[refArray.length - 1]; + const data = JSON.stringify({ + "ref": ref, + "repository": { + "html_url": "https://git-codecommit." + event.Records[0].awsRegion + ".amazonaws.com/v1/repos/" + repoName, + "default_branch": branch + } + }); + console.log(data); + + const options = { + hostname: event.Records[0].customData, + path: '/api/webhook', + method: 'POST', + port: 443, + headers: { + 'Content-Type': 'application/json', + 'X-GitHub-Event': 'push', + 'Content-Length': data.length, + }, + }; + + const promise = new Promise(function(resolve, reject) { + process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; + const req = https.request(options, (res) => { + resolve(res.statusCode); + }).on('error', (e) => { + reject(Error(e)); + }); + req.write(data); + req.end(); + }); + return promise; +}; \ No newline at end of file