add-vault-tokens 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c2ea61f5ded8622f219284aa593c3bf3eadffc4f
4
+ data.tar.gz: a942ee2017815d29029d7ccec464e00fa8257dd3
5
+ SHA512:
6
+ metadata.gz: 6e7a3201cf312533813f87dd2a3ccb9b1eef0136b0f1ea1b16c63b6e750ec0012f9da0bb503fda9f461c11d2053953f56f6a1c50113338c22dfab8d7158377e4
7
+ data.tar.gz: eb1ae0b74599ae7201ac2629478210e72461506a9eacf39658ba110594a049f3cb5a30def389cc262bc1c635dff92c4213207520961d79b616d5b7971925b882
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in add_vault_tokens.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Eric Kidd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,114 @@
1
+ # `add-vault-tokens`
2
+
3
+ This is a short script for use with [vault](https://vaultproject.io/) and
4
+ [docker-compose](https://docs.docker.com/compose/). Given a
5
+ `docker-compose.yml` file and a `VAULT_MASTER_TOKEN` as input, this script
6
+ will generate a new, limited vault token for each application described in
7
+ the `docker-compose.yml` file.
8
+
9
+ You can install this as:
10
+
11
+ ```sh
12
+ gem install add-vault-tokens
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Assume you have a `docker-compose.yml` containing:
18
+
19
+ ```yml
20
+ app:
21
+ image: "example/app"
22
+
23
+ service:
24
+ image: "example/service"
25
+ ```
26
+
27
+ First, you need to create a security policy `master-token.hcl` for the
28
+ master token:
29
+
30
+ ```hcl
31
+ # Mandatory for all policies.
32
+ path "auth/token/lookup-self" {
33
+ policy = "read"
34
+ }
35
+
36
+ # Allow listing all available policies, so we can decide which child tokens
37
+ # to generate.
38
+ path "sys/policy" {
39
+ policy = "sudo"
40
+ }
41
+
42
+ # Allow creation of child tokens.
43
+ path "auth/token/create" {
44
+ policy = "write"
45
+ }
46
+
47
+ # Allow renewal of this token.
48
+ #
49
+ # SECURITY - HACK - We can't just allow renewal via `renew-self` in 0.3, so
50
+ # allow renewal of _any_ token as the next best substitute.
51
+ path "auth/token/renew/*" {
52
+ policy = "sudo"
53
+ }
54
+ ```
55
+
56
+ This can be loaded using:
57
+
58
+ ```sh
59
+ vault policy-write master-token master-token.hcl
60
+ ```
61
+
62
+ Then you need to define two new policies, `app` and `service`, specifying
63
+ which secrets can be accessed by each container. Once this is done, you
64
+ can create your `VAULT_MASTER_TOKEN` for use with `add-vault-tokens`:
65
+
66
+ ```sh
67
+ vault token-create -policy=master-token -policy=app -policy=service
68
+ ```
69
+
70
+ Then you run `add-vault-tokens` as follows:
71
+
72
+ ```
73
+ # The URL of your vault server.
74
+ export VAULT_ADDR=https://...
75
+
76
+ # The master token you just generated.
77
+ export VAULT_MASTER_TOKEN=...
78
+
79
+ # Generate tokens
80
+ add-vault-tokens docker-compose.yml
81
+ ```
82
+
83
+ This will update `docker-compose.yml` to include new environment variables:
84
+
85
+ ```yml
86
+ app:
87
+ image: "example/app"
88
+ environment:
89
+ VAULT_ADDR="https://..."
90
+ # A new token with policy "app":
91
+ VAULT_TOKEN="..."
92
+
93
+ service:
94
+ image: "example/service"
95
+ environment:
96
+ VAULT_ADDR="https://..."
97
+ # A new token with policy "service":
98
+ VAULT_TOKEN="..."
99
+ ```
100
+
101
+ If a `VAULT_ENV` environment variable is present, it will also be added to
102
+ the `docker-compose.yml` file, and the policy names will be prefixed by
103
+ `$VAULT_ENV-`.
104
+
105
+ ## Contributing
106
+
107
+ Bug reports and pull requests are welcome on GitHub at
108
+ https://github.com/faradayio/add-vault-tokens.
109
+
110
+ ## License
111
+
112
+ The gem is available as open source under the terms of the
113
+ [MIT License](http://opensource.org/licenses/MIT).
114
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'add_vault_tokens/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "add-vault-tokens"
8
+ spec.version = AddVaultTokens::VERSION
9
+ spec.authors = ["Eric Kidd"]
10
+ spec.email = ["git@randomhacks.net"]
11
+
12
+ spec.summary = %q{Issue per-application Vault tokens to apps in docker-compose.yml}
13
+ spec.description = %q{Given a master vault token, issue short-lived, per-application tokens to each app in a docker-compose.yml file, restricting each app the to corresponding security policy.}
14
+ spec.homepage = "https://github.com/faradayio/add-vault-tokens"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "vault"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "add_vault_tokens"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "psych"
5
+ require "add_vault_tokens"
6
+
7
+ # Set up command-line option defaults.
8
+ options = { prefix: '' }
9
+ options[:prefix] = "#{ENV.fetch('VAULT_ENV')}-" if ENV.has_key?('VAULT_ENV')
10
+
11
+ # Parse our command-line.
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: example.rb [options]"
14
+
15
+ opts.on("-p", "--prefix", "Prefix to add to each app name") do |p|
16
+ options[:prefix] = p
17
+ end
18
+ end.parse!
19
+ paths = ARGV
20
+
21
+ # Connect to our vault server.
22
+ AddVaultTokens.connect
23
+
24
+ # Renew our master token.
25
+ STDERR.puts("Renewing VAULT_MASTER_TOKEN")
26
+ AddVaultTokens.renew_master_token
27
+
28
+ # For each input file, add the appropriate tokens to each app.
29
+ paths.each do |path|
30
+ yml = Psych.load_file(path)
31
+ result = AddVaultTokens.add_tokens_to_apps(yml, prefix: options.fetch(:prefix))
32
+ File.write("#{path}.tmp", Psych.dump(result))
33
+ # Atomically overwrite existing file.
34
+ File.rename("#{path}.tmp", path)
35
+ end
@@ -0,0 +1,2 @@
1
+ # Load our real main file.
2
+ require 'add_vault_tokens'
@@ -0,0 +1,58 @@
1
+ require "vault"
2
+ require "add_vault_tokens/version"
3
+
4
+ module AddVaultTokens
5
+ class << self
6
+ # Connect if we haven't already.
7
+ def connect
8
+ return if @connected
9
+ @connected = true
10
+ Vault.address = ENV.fetch('VAULT_ADDR')
11
+ Vault.token = ENV.fetch('VAULT_MASTER_TOKEN')
12
+ end
13
+
14
+ # Does our vault have a policy for app_name?
15
+ def have_policy_for?(app_name)
16
+ @policies ||= Vault.sys.policies
17
+ @policies.include?(app_name)
18
+ end
19
+
20
+ # Renew our master token. We do this in case it's getting old, in
21
+ # which case we don't want to risk our generated tokens expiring early.
22
+ def renew_master_token
23
+ # TODO: Use renew_self as soon as it's available, so we don't need
24
+ # the power to renew any arbitrary token.
25
+ Vault.auth_token.renew(ENV.fetch('VAULT_MASTER_TOKEN'))
26
+ end
27
+
28
+ # Create a token for app_name with the appropriate security policy.
29
+ def create_token_for(app_name)
30
+ Vault.auth_token.create(name: app_name,
31
+ ttl: '720h',
32
+ policies: [app_name])
33
+ end
34
+
35
+ # Given a parsed `docker-compose.yml` file, return a new version with
36
+ # appropriate vault-related environment variables injected. If
37
+ # specified, append `prefix` to each service name in the file before
38
+ # looking up a policy.
39
+ def add_tokens_to_apps(parsed_yaml, prefix: "")
40
+ env = ENV.fetch('VAULT_ENV', nil)
41
+ result = Marshal.load(Marshal.dump(parsed_yaml))
42
+ result.each do |app_name, info|
43
+ full_app_name = prefix + app_name
44
+ if have_policy_for?(full_app_name)
45
+ STDERR.puts("Issuing token for #{full_app_name}")
46
+ token = create_token_for(full_app_name)
47
+ info['environment'] ||= {}
48
+ info['environment']['VAULT_ADDR'] = ENV.fetch('VAULT_ADDR')
49
+ info['environment']['VAULT_ENV'] = env if env
50
+ info['environment']['VAULT_TOKEN'] = token.auth.client_token
51
+ else
52
+ STDERR.puts("WARNING: No policy for #{full_app_name}, so no token issued")
53
+ end
54
+ end
55
+ result
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module AddVaultTokens
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: add-vault-tokens
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eric Kidd
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: vault
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Given a master vault token, issue short-lived, per-application tokens
70
+ to each app in a docker-compose.yml file, restricting each app the to corresponding
71
+ security policy.
72
+ email:
73
+ - git@randomhacks.net
74
+ executables:
75
+ - add-vault-tokens
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - ".rspec"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - add-vault-tokens.gemspec
87
+ - bin/console
88
+ - bin/setup
89
+ - exe/add-vault-tokens
90
+ - lib/add-vault-tokens.rb
91
+ - lib/add_vault_tokens.rb
92
+ - lib/add_vault_tokens/version.rb
93
+ homepage: https://github.com/faradayio/add-vault-tokens
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.4.5
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Issue per-application Vault tokens to apps in docker-compose.yml
117
+ test_files: []