diff --git a/app/lib/clients/vault.rb b/app/lib/clients/vault.rb index 78d496c..42cf3c9 100644 --- a/app/lib/clients/vault.rb +++ b/app/lib/clients/vault.rb @@ -1,23 +1,21 @@ module Clients class Vault + class_attribute :token + class << self private def client ::Vault::Client.new( - address: vault_address, - token: vault_token + address: address, + token: token ) end - def vault_address + def address Config[:vault_addr] end - def vault_token - Config[:vault_token] - end - def enable_engine(mount, type) client.sys.mount(mount, type, "#{type} secrets engine") end @@ -26,6 +24,7 @@ def enable_engine(mount, type) require_relative "vault/key_value" require_relative "vault/certificate" + require_relative "vault/policy" require_relative "vault/entity" require_relative "vault/entity_alias" end diff --git a/app/lib/clients/vault/certificate.rb b/app/lib/clients/vault/certificate.rb index 7b3f57a..4469d5a 100644 --- a/app/lib/clients/vault/certificate.rb +++ b/app/lib/clients/vault/certificate.rb @@ -64,8 +64,8 @@ def configure_root_ca File.write("tmp/#{root_ca_mount}.crt", root_cert) client.logical.write("#{root_ca_mount}/config/cluster", - path: "#{vault_address}/v1/#{root_ca_mount}", - aia_path: "#{vault_address}/v1/#{root_ca_mount}") + path: "#{address}/v1/#{root_ca_mount}", + aia_path: "#{address}/v1/#{root_ca_mount}") client.logical.write("#{root_ca_mount}/config/urls", issuing_certificates: "{{cluster_aia_path}}/issuer/{{issuer_id}}/der", @@ -100,8 +100,8 @@ def sign_cert def configure_ca # Configure the intermediate CA client.logical.write("#{intermediate_ca_mount}/config/cluster", - path: "#{vault_address}/v1/#{intermediate_ca_mount}", - aia_path: "#{vault_address}/v1/#{intermediate_ca_mount}") + path: "#{address}/v1/#{intermediate_ca_mount}", + aia_path: "#{address}/v1/#{intermediate_ca_mount}") # Configure the role for issuing certs issuer_ref = client.logical.read("#{intermediate_ca_mount}/config/issuers").data[:default] diff --git a/app/lib/clients/vault/key_value.rb b/app/lib/clients/vault/key_value.rb index 375827f..c11f9f3 100644 --- a/app/lib/clients/vault/key_value.rb +++ b/app/lib/clients/vault/key_value.rb @@ -6,7 +6,6 @@ def kv_read(path) end def kv_write(path, data) - configure_kv client.logical.write("#{kv_mount}/data/#{path}", data: data) end diff --git a/app/lib/clients/vault/policy.rb b/app/lib/clients/vault/policy.rb new file mode 100644 index 0000000..13ad3a5 --- /dev/null +++ b/app/lib/clients/vault/policy.rb @@ -0,0 +1,37 @@ +module Clients + class Vault + class << self + def rotate_token + create_astral_policy + token = create_astral_token + Clients::Vault.token = token + end + + private + + def create_astral_policy + policy = <<-HCL + path "#{intermediate_ca_mount}/roles/astral" { + capabilities = ["read", "list"] + } + path "#{intermediate_ca_mount}/issue/astral" { + capabilities = ["create", "update"] + } + path "#{kv_mount}/data/*" { + capabilities = ["create", "read", "update", "delete", "list"] + } + HCL + + client.sys.put_policy("astral_policy", policy) + end + + def create_astral_token + token = client.auth_token.create( + policies: [ "astral_policy" ], + ttl: "24h" + ) + token.auth.client_token + end + end + end +end diff --git a/config/application.rb b/config/application.rb index 028787f..c3cdf58 100644 --- a/config/application.rb +++ b/config/application.rb @@ -33,8 +33,11 @@ class Application < Rails::Application config.astral = config_for :astral config.after_initialize do + # bootstrap with provided token, then rotate + Clients::Vault.token = Config[:vault_token] Clients::Vault.configure_kv Clients::Vault.configure_pki + Clients::Vault.rotate_token end end end diff --git a/test/lib/clients/vault_test.rb b/test/lib/clients/vault_test.rb index 2312e82..e18337c 100644 --- a/test/lib/clients/vault_test.rb +++ b/test/lib/clients/vault_test.rb @@ -3,32 +3,38 @@ class VaultTest < ActiveSupport::TestCase attr_reader :intermediate_ca_mount attr_reader :root_ca_mount + attr_reader :kv_mount attr_reader :policies attr_reader :entity_name attr_reader :alias_name + setup do @client = Clients::Vault + @token = Clients::Vault.token + Clients::Vault.token = vault_token @root_ca_mount = SecureRandom.hex(4) @intermediate_ca_mount = SecureRandom.hex(4) + @kv_mount = SecureRandom.hex(4) @policies = SecureRandom.hex(4) @entity_name = SecureRandom.hex(4) @alias_name = SecureRandom.hex(4) - end + end teardown do + Clients::Vault.token = @token vault_client.sys.unmount(root_ca_mount) vault_client.sys.unmount(intermediate_ca_mount) end - test "#configure_kv" do - @client.stub :kv_mount, intermediate_ca_mount do + test ".configure_kv" do + @client.stub :kv_mount, kv_mount do assert @client.configure_kv engines = vault_client.sys.mounts - assert_equal "kv", engines[intermediate_ca_mount.to_sym].type + assert_equal "kv", engines[kv_mount.to_sym].type end end - test "#configure_pki" do + test ".configure_pki" do @client.stub :root_ca_mount, root_ca_mount do @client.stub :intermediate_ca_mount, intermediate_ca_mount do assert @client.configure_pki @@ -53,6 +59,16 @@ class VaultTest < ActiveSupport::TestCase end end + test ".rotate_token" do + # begins with default token + assert_equal vault_token, @client.token + assert @client.rotate_token + # now has a new token + assert_not_equal vault_token, @client.token + # ensure we can write with the new token + assert_instance_of Vault::Secret, @client.kv_write("testing/secret", { password: "sicr3t" }) + end + test "#entity" do entity = @client.read_entity(@entity_name) assert_nil entity @@ -99,11 +115,15 @@ class VaultTest < ActiveSupport::TestCase def vault_client ::Vault::Client.new( address: vault_addr, - token: Config[:vault_token] + token: vault_token ) end def vault_addr Config[:vault_addr] end + + def vault_token + Config[:vault_token] + end end