-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #158 from ybezsonov/argocd-codecommit
feat: add pattern for ArgoCD workloads in AWS CodeCommit
- Loading branch information
Showing
9 changed files
with
374 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -254,6 +254,7 @@ Patterns: | |
snyk | ||
starter | ||
gmaestro | ||
workloads-codecommit | ||
``` | ||
- Bootstrap your CDK environment. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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'); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# 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 <your 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 | ||
``` | ||
|
||
## Get ArgoCD Url and credentials | ||
|
||
```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 CC_REPO_NAME=eks-blueprints-workloads-cc | ||
|
||
echo "ArgoCD URL: https://$ARGOCD_SERVER" | ||
echo "ArgoCD server user: admin" | ||
echo "ArgoCD admin password: $(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d)" | ||
``` | ||
|
||
## Create notification trigger from AWS CodeCommit push to ArgoCD Sync | ||
|
||
```bash | ||
export LAMBDA_ARN=$(aws lambda get-function --function-name eks-blueprints-workloads-cc-webhook | jq -r .Configuration.FunctionArn) | ||
|
||
cat > trigger.json <<EOF | ||
[ | ||
{ | ||
"destinationArn": "${LAMBDA_ARN}", | ||
"branches": [], | ||
"name": "${CC_REPO_NAME}-trigger", | ||
"customData": "${ARGOCD_SERVER}", | ||
"events": [ | ||
"all" | ||
] | ||
} | ||
] | ||
EOF | ||
|
||
aws codecommit put-repository-triggers --repository-name $CC_REPO_NAME --triggers file://trigger.json --no-cli-pager | ||
rm trigger.json | ||
``` | ||
|
||
## Set AWS_REGION | ||
|
||
```bash | ||
export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]') | ||
echo $AWS_REGION | ||
``` | ||
|
||
## Populate AWS CodeCommit with Blueprint workloads Sample repository | ||
|
||
```bash | ||
pushd .. | ||
git clone https://github.com/aws-samples/eks-blueprints-workloads.git | ||
git clone codecommit::$AWS_REGION://$CC_REPO_NAME | ||
cd $CC_REPO_NAME | ||
git checkout -b main | ||
cd .. | ||
rsync -av eks-blueprints-workloads/ $CC_REPO_NAME --exclude .git | ||
cd $CC_REPO_NAME | ||
git add . && git commit -m "initial commit" && git push --set-upstream origin main | ||
popd | ||
``` | ||
|
||
ArgoCD will receive notification and will start sync. | ||
|
||
![ArgoCD sync](./images/argocd-cc-workloads.png) | ||
|
||
## Destroy | ||
|
||
To teardown and remove the resources created in this example: | ||
|
||
1. Delete "bootstrap-apps" project in ArgoCD UI and wait until ArgoCD delete workloads | ||
|
||
2. Delete deployed resources | ||
|
||
```sh | ||
cd cdk-eks-blueprints-patterns | ||
make pattern workloads-codecommit destroy | ||
``` | ||
|
||
3. Delete cloned repositories (`if necessary`) | ||
|
||
```sh | ||
pushd .. | ||
rm -rf eks-blueprints-workloads-cc | ||
rm -rf eks-blueprints-workloads | ||
popd | ||
``` |
43 changes: 43 additions & 0 deletions
43
lib/workloads-codecommit-construct/codecommit-credentials.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, PhysicalResourceIdReference } from 'aws-cdk-lib/custom-resources'; | ||
import { Construct } from 'constructs'; | ||
|
||
export class CodeCommitCredentials extends Construct { | ||
readonly serviceSpecificCredentialId: string; | ||
readonly serviceName: string; | ||
readonly serviceUserName: string; | ||
readonly servicePassword: string; | ||
readonly status: string; | ||
|
||
constructor(scope: Construct, id: string, userName: string) { | ||
super(scope, id); | ||
|
||
const codeCommitCredentialsResponse = new AwsCustomResource(this, "codecommit-credentials-custom-resource", { | ||
onCreate: { | ||
service: "IAM", | ||
action: "createServiceSpecificCredential", | ||
parameters: { | ||
ServiceName: "codecommit.amazonaws.com", | ||
UserName: userName | ||
}, | ||
physicalResourceId: PhysicalResourceId.fromResponse("ServiceSpecificCredential.ServiceSpecificCredentialId") | ||
}, | ||
onDelete: { | ||
service: "IAM", | ||
action: "deleteServiceSpecificCredential", | ||
parameters: { | ||
ServiceSpecificCredentialId: new PhysicalResourceIdReference(), | ||
UserName: userName, | ||
} | ||
}, | ||
policy: AwsCustomResourcePolicy.fromSdkCalls({ | ||
resources: AwsCustomResourcePolicy.ANY_RESOURCE, | ||
}), | ||
}); | ||
|
||
this.serviceSpecificCredentialId = codeCommitCredentialsResponse.getResponseField("ServiceSpecificCredential.ServiceSpecificCredentialId"); | ||
this.serviceName = codeCommitCredentialsResponse.getResponseField("ServiceSpecificCredential.ServiceName"); | ||
this.serviceUserName = codeCommitCredentialsResponse.getResponseField("ServiceSpecificCredential.ServiceUserName"); | ||
this.servicePassword = codeCommitCredentialsResponse.getResponseField("ServiceSpecificCredential.ServicePassword"); | ||
this.status = codeCommitCredentialsResponse.getResponseField("ServiceSpecificCredential.Status"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import * as blueprints from '@aws-quickstart/eks-blueprints'; | ||
import { Construct } from 'constructs'; | ||
import WorkloadsCodeCommitRepoStack from './workloads-codecommit-repo-stack'; | ||
|
||
/** | ||
* Demonstrates how to use AWS CodeCommmit as a repository for ArgoCD workloads. | ||
*/ | ||
|
||
export default class WorkloadsCodeCommitConstruct extends Construct { | ||
constructor(scope: Construct, id: string) { | ||
super(scope, id); | ||
|
||
const region = process.env.CDK_DEFAULT_REGION!; | ||
|
||
const userName = 'argocd-cc'; | ||
const repoName = 'eks-blueprints-workloads-cc'; | ||
|
||
const repoUrl = 'https://git-codecommit.' + region + '.amazonaws.com/v1/repos/' + repoName; | ||
|
||
const stackId = `${id}-blueprint`; | ||
|
||
const bootstrapRepo : blueprints.ApplicationRepository = { | ||
repoUrl, | ||
targetRevision: 'main', | ||
credentialsSecretName: repoName + '-codecommit-secret', | ||
credentialsType: 'TOKEN' | ||
}; | ||
|
||
const addOns: Array<blueprints.ClusterAddOn> = [ | ||
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}; |
54 changes: 54 additions & 0 deletions
54
lib/workloads-codecommit-construct/workloads-codecommit-repo-stack.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Construct } from 'constructs'; | ||
import { NestedStack, NestedStackProps, SecretValue } from 'aws-cdk-lib'; | ||
import * as blueprints from '@aws-quickstart/eks-blueprints'; | ||
import * as codecommit from 'aws-cdk-lib/aws-codecommit'; | ||
import * as iam from 'aws-cdk-lib/aws-iam'; | ||
import * as lambda from 'aws-cdk-lib/aws-lambda'; | ||
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager'; | ||
import { CodeCommitCredentials } from './codecommit-credentials'; | ||
|
||
export default class WorkloadsCodeCommitRepoStack extends NestedStack { | ||
public static builder(userName: string, repoName: string): blueprints.NestedStackBuilder { | ||
return { | ||
build(scope: Construct, id: string, props: NestedStackProps) { | ||
return new WorkloadsCodeCommitRepoStack(scope, id, props, userName, repoName); | ||
} | ||
}; | ||
} | ||
|
||
constructor(scope: Construct, id: string, props: NestedStackProps, userName: string, repoName: string) { | ||
super(scope, id); | ||
|
||
const repo = new codecommit.Repository(this, repoName + '-codecommit-repo', { | ||
repositoryName: repoName, | ||
}); | ||
|
||
const user = new iam.User(this, userName + '-user-name', { | ||
userName: userName, | ||
}); | ||
repo.grantPull(user); | ||
|
||
const credentials = new CodeCommitCredentials(this, "codecommit-credentials", user.userName); | ||
credentials.node.addDependency(user); | ||
|
||
new secretsmanager.Secret(this, 'codecommit-secret', { | ||
secretObjectValue: { | ||
username: SecretValue.unsafePlainText(credentials.serviceUserName), | ||
password: SecretValue.unsafePlainText(credentials.servicePassword), | ||
url: SecretValue.unsafePlainText(repo.repositoryCloneUrlHttp) | ||
}, | ||
secretName: repoName + '-codecommit-secret' | ||
}); | ||
|
||
const fn = new lambda.Function(this, repoName + '-webhook', { | ||
runtime: lambda.Runtime.NODEJS_20_X, | ||
functionName: repoName + '-webhook', | ||
description: 'Webhook for ArgoCD on commit to AWS CodeCommit', | ||
handler: 'index.handler', | ||
code: lambda.Code.fromAsset("lib/workloads-codecommit-construct/lambda"), | ||
}); | ||
|
||
const principal = new iam.ServicePrincipal('codecommit.amazonaws.com'); | ||
fn.grantInvoke(principal); | ||
} | ||
} |