Skip to content

Commit

Permalink
Merge pull request #17 from anoldguy/switch-to-docker-secrets
Browse files Browse the repository at this point in the history
Enable docker secrets as a more secure alternative to build args
  • Loading branch information
dhh authored Jan 20, 2023
2 parents fe453ed + 9bb1fb7 commit 4434b6e
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 17 deletions.
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,26 +146,44 @@ builder:
multiarch: false
```

### Configuring build secrets for new images

Some images need a secret passed in during build time, like a GITHUB_TOKEN to give access to private gem repositories. This can be done by having the secret in ENV, then referencing it like so in the configuration:

```yaml
builder:
secrets:
- GITHUB_TOKEN
```

This build secret can then be used in the Dockerfile:

```
# Install application gems
COPY Gemfile Gemfile.lock ./
# Private repositories need an access token during the build
RUN --mount=type=secret,id=GITHUB_TOKEN \
BUNDLE_GITHUB__COM=x-access-token:$(cat /run/secrets/GITHUB_TOKEN) \
bundle install
```

### Configuring build args for new images

Some images might need an argument passed in during build time, like a GITHUB_TOKEN to give access to private gem repositories. This can be done like so:
Build arguments that aren't secret can be configured like so:

```yaml
builder:
args:
GITHUB_TOKEN: <%= ENV["GITHUB_TOKEN"] %>
RUBY_VERSION: 3.2.0
```

This build arg can then be used in the Dockerfile:
This build argument can then be used in the Dockerfile:

```
# Private repositories need an access token during the build
ARG GITHUB_TOKEN
ENV BUNDLE_GITHUB__COM=x-access-token:$GITHUB_TOKEN
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install
ARG RUBY_VERSION
FROM ruby:$RUBY_VERSION-slim as base
```

## Commands
Expand Down
10 changes: 9 additions & 1 deletion lib/mrsk/commands/builder/base.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "mrsk/commands/base"

class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base
delegate :argumentize, to: Mrsk::Configuration
delegate :argumentize, to: Mrsk::Utils

def pull
docker :pull, config.absolute_image
Expand All @@ -11,8 +11,16 @@ def build_args
argumentize "--build-arg", args, redacted: true
end

def build_secrets
argumentize "--secret", secrets.collect { |secret| [ "id", secret ] }
end

private
def args
config.builder["args"] || {}
end

def secrets
config.builder["secrets"] || []
end
end
9 changes: 3 additions & 6 deletions lib/mrsk/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class Mrsk::Configuration
delegate :service, :image, :servers, :env, :labels, :registry, :builder, to: :config, allow_nil: true
delegate :argumentize, to: Mrsk::Utils

class << self
def create_from(base_config_file, destination: nil)
Expand All @@ -18,10 +19,6 @@ def create_from(base_config_file, destination: nil)
end)
end

def argumentize(argument, attributes, redacted: false)
attributes.flat_map { |k, v| [ argument, redacted ? Mrsk::Utils.redact("#{k}=#{v}") : "#{k}=#{v}" ] }
end

private
def load_config_file(file)
if file.exist?
Expand Down Expand Up @@ -94,7 +91,7 @@ def service_with_version

def env_args
if config.env.present?
self.class.argumentize "-e", config.env
argumentize "-e", config.env
else
[]
end
Expand Down Expand Up @@ -137,7 +134,7 @@ def ensure_required_keys_present

if config.registry["username"].blank?
raise ArgumentError, "You must specify a username for the registry in config/deploy.yml"
end
end

if config.registry["password"].blank?
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
Expand Down
2 changes: 1 addition & 1 deletion lib/mrsk/configuration/role.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Mrsk::Configuration::Role
delegate :argumentize, to: Mrsk::Configuration
delegate :argumentize, to: Mrsk::Utils

attr_accessor :name

Expand Down
5 changes: 5 additions & 0 deletions lib/mrsk/utils.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
module Mrsk::Utils
extend self

# Return a list of shell arguments using the same named argument against the passed attributes.
def argumentize(argument, attributes, redacted: false)
attributes.flat_map { |k, v| [ argument, redacted ? redact("#{k}=#{v}") : "#{k}=#{v}" ] }
end

# Copied from SSHKit::Backend::Abstract#redact to be available inside Commands classes
def redact(arg) # Used in execute_command to hide redact() args a user passes in
arg.to_s.extend(SSHKit::Redaction) # to_s due to our inability to extend Integer, etc
Expand Down
5 changes: 5 additions & 0 deletions test/commands/builder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ class CommandsBuilderTest < ActiveSupport::TestCase
assert_equal [ "--build-arg", "a=1", "--build-arg", "b=2" ], builder.target.build_args
end

test "build secrets" do
builder = Mrsk::Commands::Builder.new(Mrsk::Configuration.new(@config.merge({ builder: { "secrets" => ["token_a", "token_b"] } })))
assert_equal [ "--secret", "id=token_a", "--secret", "id=token_b" ], builder.target.build_secrets
end

test "native push with build args" do
builder = Mrsk::Commands::Builder.new(Mrsk::Configuration.new(@config.merge({ builder: { "multiarch" => false, "args" => { "a" => 1, "b" => 2 } } })))
assert_equal [ :docker, :build, "-t", "--build-arg", "a=1", "--build-arg", "b=2", "dhh/app:123", ".", "&&", :docker, :push, "dhh/app:123" ], builder.push
Expand Down

0 comments on commit 4434b6e

Please sign in to comment.