copilot-cli icon indicating copy to clipboard operation
copilot-cli copied to clipboard

Support --secret and --ssh flags in docker build args for buildkit

Open bvtujo opened this issue 4 years ago • 23 comments
trafficstars

Similar to #1555, we should consider supporting the --secret and --ssh flags in our calls to Docker Build. This is a feature of buildkit which can help customers with builds requiring authentication to private repositories or private key files.

bvtujo avatar Mar 22 '21 22:03 bvtujo

This would definitely be useful. Supporting both --secret and --ssh flags would allow for projects to use deploy keys for private repositories without leaving traces in the final image.

ColeDCrawford avatar Mar 22 '21 23:03 ColeDCrawford

+1. This one is much needed. Thanks, we have been struggling with a bunch of workarounds. This would help.

rmarapp-dio avatar Mar 26 '21 17:03 rmarapp-dio

+1

RobinVds avatar Apr 15 '21 23:04 RobinVds

I need to access a private github repo when building the docker image.

I 've read the most secure way would be to use the --ssh flag.

Can you point me to any workaround to this?

Is it possible to pass build arguments using --build-arg? I wouldn't pass the key as an environment variable as I 'm afraid it ends up available on the running container.

Maybe I end up using subst on the Dockerfile and then using multi-stage build to "erase" the value

nbarrera avatar Jul 30 '21 12:07 nbarrera

What's currently the best way to do this? Pass an SSH key using the image.build.args? The SSH key can be stored and referenced from AWS Secrets Manager so it's not in the manifest (and therefore not visible in the repo) but it will still show in the Dockerfile build history, correct?

sribas avatar Aug 05 '21 16:08 sribas

Hey there! Any update on that feature please? We are now using private npm modules and we need the --secret option in the docker build command. Any idea how to do that?

Kylir avatar Oct 07 '21 11:10 Kylir

I was able to open source the two private dependency repos we had, but the way I handled this previously was to build the image with buildkit and the SSH args and then reference the image in the copilot manifest.yml. Not ideal but it works. Setting up CD with that would be a bit trickier though - I have a nice flow for projects with Github Actions and you'd have to do some extra steps there rather than just copilot svc deploy.

ColeDCrawford avatar Oct 07 '21 13:10 ColeDCrawford

Thanks @ColeDCrawford for the answer. In my case I have a Copilot Pipeline and I want to build on AWS pulling private NPM modules hosted by Github. Really not sure how to handle that.

Kylir avatar Oct 07 '21 21:10 Kylir

Hi @Kylir ! Thank you very much for the inquiry

Apologies 🙇🏼‍♀️ ! At this moment, this feature isn't in our short term roadmap yet. Here is our sprint board that shows the ongoing features that we are currently working on.

For the time being, would customizing the buildspec.yml work for your use case? You can add --secret flag at this line in your buildspec.

Lou1415926 avatar Oct 07 '21 21:10 Lou1415926

Hi @Lou1415926 , Thanks for the post. You are very correct. It is exactly what I'm doing right now! I declared some parameters taken from Parameter Store and tweaked the docker build command. It's still work in progress... But it looks promising.

Kylir avatar Oct 07 '21 21:10 Kylir

Update! It's working! Yeah! I've been able to pull private NPM modules from Github.

In case it is useful to anyone, here is what I did:

Secret in the Parameter Store

First I created my secret in the AWS Parameter Store. Let's name it SUPER_SECRET

Edit build file

Then, I created a Copilot pipeline: copilot pipeline init This created a buildspec.yml file that I edited. At the top I declared an env variable from the parameter store

# Buildspec runs in the build stage of your pipeline.
version: 0.2
env:
    parameter-store:
        SUPER_SECRET: SUPER_SECRET
phases:
  install:
    runtime-versions:
      docker: 18

Then, almost at the bottom I changed the docker build command for those 3 lines:

export DOCKER_BUILDKIT=1
echo $SUPER_SECRET > secret.txt
docker build --secret id=secret,src=secret.txt -t $workload:$tag $build_args-f $df_path $df_dir_path;          

Use the secret

Finally I'm using this secret in the Dockerfile to set an env variable that contains my secret.

RUN --mount=type=secret,id=secret export NPM_TOKEN=$(cat /run/secrets/secret) && npm install --production

Source: Docker

Kylir avatar Oct 07 '21 22:10 Kylir

I have a use case where we need the --ssh flag, I think I will take this on since it seems like a straightforward first task to get familiar with the copilot codebase. However, I was wondering if a better approach would be to support arbitrary extra flags doing something like:

image:
  build:
    dockerfile: Dockerfile
    build_flags: ['--ssh', 'default']

Rather than

image:
  build:
    dockerfile: Dockerfile
    ssh: default

I just worry that it will be a never-ending game of whack-a-mole trying to support every possible docker build parameter that somebody might need.

A potential counter-argument to build_flags is that so far this yaml config seems to be trying to mirror the same compose build: functionality. Unfortunately compose doesn't support --ssh yet either so there's not a pattern to follow there. I see a few unresolved issues such as https://github.com/compose-spec/compose-spec/issues/81 that have been discussed for a couple years without resolution.

codekitchen avatar Dec 17 '21 16:12 codekitchen

Hello!

[EDIT: to make it clear I need my secret in a pipeline.]

I need a bit of help please.

My Copilot services are all built automatically using a Copilot Pipeline. At build time they need a token (NPM_TOKEN) to pull the private npm packages we have in the Github package registry. This token is declared in my Copilot secrets (aka in the Parameter Store)

With the previous versions of Copilot I could editing the Pipeline buildspec.xml and manually add the build arguments I needed.

Lately I updated Copilot and the new pipeline config files are hiding the image building details. The documentation is pointing to a manifest arguments called build.args, am I correct thinking this is the --build-args used by docker?

I modified my manifest to include this image section:

image:
    build: Dockerfile
    args:
        NPM_TOKEN: NPM_TOKEN
    port: 80

But this is not working. It looks like the parameter is expecting a value, not a secret.

How can I pass my token from the parameter store to the docker build arguments, any idea?

Thanks!

Kylir avatar May 19 '22 17:05 Kylir

Hello @Kylir.

The documentation is pointing to a manifest arguments called build.args, am I correct thinking this is the --build-args used by docker?

Yes this is correct.

How can I pass my token from the parameter store to the docker build arguments, any idea?

I think this might be helpful as Copilot codebuild allows SSM read permission so that you can possibly use aws cli to call SSM api to get the secret and pass the secret value to image.args using manifest environment variables.

NPM_TOKEN=$(aws ssm get-parameter --name "MyStringParameter")

and then the service manifest

image:
    build: Dockerfile
    args:
        NPM_TOKEN: ${NPM_TOKEN}
    port: 80

iamhopaul123 avatar May 19 '22 17:05 iamhopaul123

Thanks a lot @iamhopaul123 for the quick answer.

Sorry, I wasn't clear. On my machine this environment variable is already there (but your solution to set it is very elegant!) My issue is to get the value inside a Copilot pipeline.

Kylir avatar May 19 '22 18:05 Kylir

Yeah the value will only be resolved inside of the CodeBuild environment. That's the reason why you would need to call the SSM api and create the env var in the buildspec file.

iamhopaul123 avatar May 19 '22 18:05 iamhopaul123

Let's see if I understand correctly: Inside buildspec.xml I can set the env variable using aws ssm?

How will the docker build pick up this variable? Will the manifest used at this point and the --build-args populated?

Sorry for not understanding... I'm used to have pipeline config files with 130 lines (including docker build) and now the files is only 82 lines... :)

Kylir avatar May 19 '22 18:05 Kylir

So buildspec.yaml is actually executed in a CodeBuild environment that Copilot creates for you after you run pipeline update. And if you put aws ssm in the buildspec file, it will run the command in that environment where we've installed docker. After that, when Copilot run copilot svc package --upload-assets, we'll substitute ${NPM_TOKEN} with the env var and run docker command to build and upload the image.

iamhopaul123 avatar May 19 '22 18:05 iamhopaul123

Thanks a ton! I will try that tomorrow (it's 8pm here :D)

Kylir avatar May 19 '22 19:05 Kylir

It's working! Thanks to your help I'm back on track!

My issue was with (my brain!) the syntax of the Manifest file. I didn't realise that I need to use the property dockerfile if I'm using the args one. So my manifest now looks like:

image:
    build:
        dockerfile: Dockerfile
        args:
            NPM_TOKEN: ${NPM_TOKEN}
    port: 80

Also, I used the env.parameter-store property in the buildspec file. so my buildspecs.yml has this at the beginning:

env:
    parameter-store:
        NPM_TOKEN: NPM_TOKEN

With this, I don't need to call aws ssn.

Thanks again for the help!

Kylir avatar May 20 '22 13:05 Kylir

Also, I used the env.parameter-store property in the buildspec file.

This is slick! Good finding and thanks for sharing it to me.

iamhopaul123 avatar May 20 '22 17:05 iamhopaul123

+1 having the --secret flag exposed in manifest would be very useful for a use case we have. For us we are using this as part of a service.

ascrookes avatar Jun 27 '23 03:06 ascrookes

👍🏼

ssyberg avatar Mar 29 '24 10:03 ssyberg