Concourse CI/CD on AWS and Custom resources
Concourse is an amazing CI/CD tool which many people choose for the ease of use and first class support of “pipeline as code” concept. I had quite a deep dive with this tool and never regret choosing to use it in production, although it comes with some quirks of its own.
Concourse is a container technology at its core and this means jobs you’re running are stateless. Yet job outputs have to be stored somewhere and Concourse achieves this with resources.
Resources are objects that are used in pipeline jobs as inputs/outputs and among other things allow storage of artifacts produced at certain stages of a pipeline. Some of the most prominent ones are S3 and Git resources.
I’ve had some teething pains with using AWS related resources like S3 and ECR. Most issues were with AWS IAM access permissions - giving resource access to a specific S3 bucket requires specifying AWS access key in Concourse pipeline YAML file, which is not ideal (there are ways to bypass this by substituting variables, etc, but this adds complexity when updating pipelines).
An obvious solution would be to use EC2 IAM Instance Profiles for Concourse worker machines. Unfortunately, Concourse devs are not extremely keen on implementing this functionality; relevant PR was closed with the following comment:
that would be a bad idea to include such feature into the s3-resource itself, due to the lack of security in the AWS metadata endpoint. If you allow a worker VM to assume a role, any container can do that.
I agree with above being a possible security hole, but in a certain environments, where all pipelines on a worker instance are trusted, using IAM instance profile pattern may help immensely.
Luckily for us, open-source nature of Concourse and all its resources comes to the rescue! One can easily fork resource repo, make necessary modifications to enable instance profile support and build/store own custom resource docker container. Under the hood, resources are simple pieces of code that implement 3 scripts: check for checking for new versions of the resource, in for pulling a version of the resource down and out for idempotently pushing a version up.
In case of S3 resource an example of updated Go code would look like this:
// Try with instance profile
creds := credentials.NewCredentials(
&ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New()),
})
cred_details, _ := creds.Get()
// If unsuccessful fall back to anonymous
if cred_details == (credentials.Value{}) {
creds = credentials.AnonymousCredentials
}
Build updated code, store it in your AWS ECR and feel free to use it in your pipelines!
Update: Since this solution was implemented, Concourse received support for AWS Parameter Store service which simplifies the task of storing secrets and makes solution above quite obsolete - https://concourse-ci.org/creds.html. Yet custom resources are still a perfectly valid method of adding functionality to your Concourse installation.
Have a look at the list of resources that community has created for Concourse - https://concourse-ci.org/community-resources.html. It’s amazing how flexible and customizable that system is!