Skip to content

Commit

Permalink
Merge branch 'main' into addEntities
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeJahad authored Oct 2, 2024
2 parents d8a4d74 + a37ec0a commit 63f3411
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"forwardPorts": [3000, 5432, 8200],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "bundle install && rake vault:setup && rake db:setup",
"postCreateCommand": "bundle install && rake db:setup",

// Configure tool-specific properties.
// "customizations": {},
Expand Down
1 change: 1 addition & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ services:
environment:
VAULT_ADDR: http://vault:8200
VAULT_TOKEN: root_token
VAULT_CREATE_ROOT: true
VAULT_ROOT_CA_MOUNT: pki
VAULT_ROOT_CA_REF: root-ca
JWT_SIGNING_KEY: jwt_secret
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ gem "bootsnap", require: false

# High-level app logic
gem "interactor", "~> 3.0"
gem "ostruct"

# Use the vault-ruby gem to interact with HashiCorp Vault
gem "vault"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ GEM
racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
ostruct (0.6.0)
parallel (1.26.2)
parser (3.3.4.2)
ast (~> 2.4.1)
Expand Down Expand Up @@ -290,6 +291,7 @@ DEPENDENCIES
interactor (~> 3.0)
jbuilder
jwt
ostruct
puma (>= 5.0)
rails (~> 7.2.1)
rubocop-rails-omakase
Expand Down
62 changes: 44 additions & 18 deletions app/lib/clients/vault/certificate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ def issue_cert(cert_issue_request)
end

def configure_pki
if enable_ca
sign_cert
configure_ca
end
# if intermediate mount exists, assume configuration is done
return if client.sys.mounts.key?(intermediate_ca_mount.to_sym)
configure_root_ca if create_root?
enable_ca
sign_cert
configure_ca
end

private
Expand All @@ -25,6 +27,11 @@ def cert_path
"#{intermediate_ca_mount}/issue/astral"
end

def create_root?
create_root_config = Rails.configuration.astral[:vault_create_root]
!!ActiveModel::Type::Boolean.new.cast(create_root_config)
end

def root_ca_ref
Rails.configuration.astral[:vault_root_ca_ref]
end
Expand All @@ -38,36 +45,55 @@ def cert_engine_type
end

def enable_ca
# if mount exists, assume configuration is done
if client.sys.mounts.key?(intermediate_ca_mount.to_sym)
return false
end

# create the mount
# create the intermediate mount
enable_engine(intermediate_ca_mount, cert_engine_type)
true
end

def configure_root_ca
return if client.sys.mounts.key?(root_ca_mount.to_sym)

# enable engine
enable_engine(root_ca_mount, cert_engine_type)

# generate root certificate
root_cert = client.logical.write("#{root_ca_mount}/root/generate/internal",
common_name: "astral.internal",
issuer_name: root_ca_ref,
ttl: "87600h").data[:certificate]
# save the root certificate
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}")

client.logical.write("#{root_ca_mount}/config/urls",
issuing_certificates: "{{cluster_aia_path}}/issuer/{{issuer_id}}/der",
crl_distribution_points: "{{cluster_aia_path}}/issuer/{{issuer_id}}/crl/der",
ocsp_servers: "{{cluster_path}}/ocsp",
enable_templating: true)
end

def sign_cert
# Generate intermediate CSR
# generate intermediate CSR
intermediate_csr = client.logical.write("#{intermediate_ca_mount}/intermediate/generate/internal",
common_name: "astral.internal Intermediate Authority",
issuer_name: "astral-intermediate").data[:csr]

# Save the intermediate CSR
File.write("tmp/pki_intermediate.csr", intermediate_csr)
# save the intermediate CSR
File.write("tmp/#{intermediate_ca_mount}.csr", intermediate_csr)

# Sign the intermediate certificate with the root CA
# sign the intermediate certificate with the root CA
intermediate_cert = client.logical.write("#{root_ca_mount}/root/sign-intermediate",
issuer_ref: root_ca_ref,
csr: intermediate_csr,
format: "pem_bundle",
ttl: "43800h").data[:certificate]

# Save the signed intermediate certificate
File.write("tmp/intermediate.cert.pem", intermediate_cert)
# save the signed intermediate certificate
File.write("tmp/#{intermediate_ca_mount}.crt", intermediate_cert)

# Set the signed intermediate certificate
# set the signed intermediate certificate
client.logical.write("#{intermediate_ca_mount}/intermediate/set-signed", certificate: intermediate_cert)
end

Expand Down
6 changes: 4 additions & 2 deletions config/astral.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
shared:
vault_addr: <%= ENV["VAULT_ADDR"] %>
vault_token: <%= ENV["VAULT_TOKEN"] %>
# Pre-existing root CA in Vault for signing intermediate created by astral

# Pre-existing root CA, or create new if requested
vault_create_root: <%= ENV["VAULT_CREATE_ROOT"] || "true" %>
vault_root_ca_ref: <%= ENV["VAULT_ROOT_CA_REF"] || "root-ca" %>
vault_root_ca_mount: <%= ENV["VAULT_ROOT_CA_MOUNT"] || "pki" %>
vault_root_ca_mount: <%= ENV["VAULT_ROOT_CA_MOUNT"] || "pki_root" %>

jwt_signing_key: <%= ENV["JWT_SIGNING_KEY"] %>
cert_ttl: <%= ENV["CERT_TTL"] %>
Expand Down
69 changes: 0 additions & 69 deletions lib/tasks/vault.rake

This file was deleted.

13 changes: 8 additions & 5 deletions test/integration/secrets_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,31 @@ class SecretsTest < ActionDispatch::IntegrationTest
end

test "#show" do
create_secret
path = create_secret
# view the secret
get secret_path("top/secret/key"), headers: { "Authorization" => "Bearer #{jwt_authorized}" }
get secret_path(path), headers: { "Authorization" => "Bearer #{jwt_authorized}" }
assert_response :success
%w[ data metadata lease_id ].each do |key|
assert_includes response.parsed_body["secret"].keys, key
end
end

test "#delete" do
create_secret
path = create_secret
# delete the secret
delete destroy_secret_path("top/secret/key"), headers: { "Authorization" => "Bearer #{jwt_authorized}" }
delete destroy_secret_path(path), headers: { "Authorization" => "Bearer #{jwt_authorized}" }
assert_response :success
end

private

def create_secret
# make a path
path = "top/secret/#{SecureRandom.hex}"
# create the secret
post secrets_path, headers: { "Authorization" => "Bearer #{jwt_authorized}" },
params: { secret: { path: "top/secret/key", data: { password: "sicr3t" } } }
params: { secret: { path: path, data: { password: "sicr3t" } } }
path
end

def remove_pki_engine
Expand Down
54 changes: 31 additions & 23 deletions test/lib/clients/vault_test.rb
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
require "test_helper"

class VaultTest < ActiveSupport::TestCase
attr_reader :random_mount
attr_reader :root_ca_mount
attr_reader :intermediate_ca_mount
attr_reader :policies
attr_reader :entity_name
attr_reader :alias_name
setup do
@client = Clients::Vault
@random_mount = SecureRandom.hex(4)
@root_ca_mount = SecureRandom.hex(4)
@intermediate_ca_mount = SecureRandom.hex(4)
@policies = SecureRandom.hex(4)
@entity_name = SecureRandom.hex(4)
@alias_name = SecureRandom.hex(4)
end
end

teardown do
vault_client.sys.unmount(random_mount)
vault_client.sys.unmount(root_ca_mount)
vault_client.sys.unmount(intermediate_ca_mount)
end

test "#configure_kv" do
@client.stub :kv_mount, random_mount do
@client.stub :kv_mount, intermediate_ca_mount do
assert @client.configure_kv
engines = vault_client.sys.mounts
assert_equal "kv", engines[random_mount.to_sym].type
assert_equal "kv", engines[intermediate_ca_mount.to_sym].type
end
end

test "#configure_pki" do
@client.stub :intermediate_ca_mount, random_mount do
assert @client.configure_pki
engines = vault_client.sys.mounts
assert_equal "pki", engines[random_mount.to_sym].type

read_cert = vault_client.logical.read("#{random_mount}/cert/ca").data[:certificate]
assert_match "BEGIN CERTIFICATE", read_cert

cluster_config = vault_client.logical.read("#{random_mount}/config/cluster").data
assert_equal "#{vault_addr}/v1/#{random_mount}", cluster_config[:path]
assert_equal "#{vault_addr}/v1/#{random_mount}", cluster_config[:aia_path]

role_config = vault_client.logical.read("#{random_mount}/roles/astral").data
assert_not_nil role_config[:issuer_ref]
assert_equal 720.hours, role_config[:max_ttl]
assert_equal true, role_config[:allow_any_name]
end
@client.stub :root_ca_mount, root_ca_mount do
@client.stub :intermediate_ca_mount, intermediate_ca_mount do
assert @client.configure_pki

[ root_ca_mount, intermediate_ca_mount ].each do |mount|
engines = vault_client.sys.mounts
assert_equal "pki", engines[mount.to_sym].type

read_cert = vault_client.logical.read("#{mount}/cert/ca").data[:certificate]
assert_match "BEGIN CERTIFICATE", read_cert

cluster_config = vault_client.logical.read("#{mount}/config/cluster").data
assert_equal "#{vault_addr}/v1/#{mount}", cluster_config[:path]
assert_equal "#{vault_addr}/v1/#{mount}", cluster_config[:aia_path]
end

role_config = vault_client.logical.read("#{intermediate_ca_mount}/roles/astral").data
assert_not_nil role_config[:issuer_ref]
assert_equal 720.hours, role_config[:max_ttl]
assert_equal true, role_config[:allow_any_name]
end
end
end

test "#entity" do
Expand Down

0 comments on commit 63f3411

Please sign in to comment.