Skip to content

Commit

Permalink
config policy for users when they make a cert request (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeJahad authored Nov 1, 2024
1 parent aa8d6dc commit e575cab
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 11 deletions.
2 changes: 1 addition & 1 deletion app/interactors/obtain_cert.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class ObtainCert < ApplicationInteractor
def call
if cert = Services::Certificate.issue_cert(context.request)
if cert = Services::Certificate.issue_cert(context.identity, context.request)
context.cert = cert
else
context.fail!(message: "Failed to issue certificate")
Expand Down
41 changes: 40 additions & 1 deletion app/lib/clients/vault/certificate.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module Clients
class Vault
module Certificate
def issue_cert(cert_issue_request)
def issue_cert(identity, cert_issue_request)
opts = cert_issue_request.attributes
# Generate the TLS certificate using the intermediate CA
tls_cert = client.logical.write(cert_path, opts)
config_user(identity)
OpenStruct.new tls_cert.data
end

Expand All @@ -15,8 +16,20 @@ def configure_pki
enable_ca
sign_cert
configure_ca
create_generic_cert_policy
end

def config_user(identity)
sub = identity.sub
email = identity.email
policies, metadata = get_entity_data(sub)
policies.append(Certificate::GENERIC_CERT_POLICY_NAME).to_set.to_a
put_entity(sub, policies, metadata)
put_entity_alias(sub, email, "oidc")
end

GENERIC_CERT_POLICY_NAME = "astral-generic-cert-policy"

private

def intermediate_ca_mount
Expand Down Expand Up @@ -117,6 +130,32 @@ def configure_ca
ocsp_servers: "{{cluster_path}}/ocsp",
enable_templating: true)
end

def get_entity_data(sub)
entity = read_entity(sub)
if entity.nil?
[ [], nil ]
else
[ entity.data[:policies], entity.data[:metadata] ]
end
end

def create_generic_cert_policy
client.sys.put_policy(GENERIC_CERT_POLICY_NAME, generic_cert_policy)
end

def generic_cert_policy
policy = <<-EOH
path "#{cert_path}" {
capabilities = ["create", "update"]
}
path "#{intermediate_ca_mount}/revoke-with-key" {
capabilities = ["update"]
}
EOH
end
end
end
end
5 changes: 3 additions & 2 deletions app/lib/clients/vault/entity.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module Clients
class Vault
module Entity
def put_entity(name, policies)
def put_entity(name, policies, metadata = {})
client.logical.write("identity/entity",
name: name,
policies: policies)
policies: policies,
metadata: metadata)
end

def read_entity(name)
Expand Down
4 changes: 2 additions & 2 deletions app/lib/services/certificate.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Services
class Certificate
class << self
def issue_cert(cert_issue_request)
impl.issue_cert(cert_issue_request)
def issue_cert(identity, cert_issue_request)
impl.issue_cert(identity, cert_issue_request)
end

private
Expand Down
1 change: 1 addition & 0 deletions app/lib/utils/oidc_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def configure

def get_client_info
app = vault_client.logical.read(WEBAPP_NAME)
raise "oidc provider not configured." if app.nil?
@client_id = app.data[:client_id]
@client_secret = app.data[:client_secret]
[ @client_id, @client_secret ]
Expand Down
1 change: 1 addition & 0 deletions app/models/identity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ class Identity
attribute :groups, array: :string, default: []

alias_attribute :sub, :subject
alias_attribute :email, :subject
alias_attribute :roles, :groups
end
3 changes: 2 additions & 1 deletion config/astral.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ shared:

initial_user_name: test
initial_user_password: test
initial_user_email: test@example.com
initial_user_email: john.doe@example.com

test:
cert_ttl: <%= 24.hours.in_seconds %>

development:
cert_ttl: <%= 24.hours.in_seconds %>

production:
vault_create_root: false
Expand Down
10 changes: 6 additions & 4 deletions test/interactors/obtain_cert_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@ def setup

test ".call success" do
request = Requests::CertIssueRequest.new
identity = Identity.new
mock = Minitest::Mock.new
mock.expect :call, @cert, [ request ]
mock.expect :call, @cert, [ identity, request ]
Services::Certificate.stub :issue_cert, mock do
context = @interactor.call(request: request)
context = @interactor.call(identity: identity, request: request)
assert context.success?
assert_equal @cert, context.cert
end
end

test ".call failure" do
request = Requests::CertIssueRequest.new
identity = Identity.new
mock = Minitest::Mock.new
mock.expect :call, nil, [ request ]
mock.expect :call, nil, [ identity, request ]
Services::Certificate.stub :issue_cert, mock do
context = @interactor.call(request: request)
context = @interactor.call({ identity: identity, request: request })
assert context.failure?
assert_nil context.cert
end
Expand Down
11 changes: 11 additions & 0 deletions test/lib/clients/vault_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class VaultTest < ActiveSupport::TestCase
@policies = SecureRandom.hex(4)
@entity_name = SecureRandom.hex(4)
@alias_name = SecureRandom.hex(4)
@identity = Identity.new
@identity.sub = SecureRandom.hex(4)
end

teardown do
Expand Down Expand Up @@ -110,6 +112,15 @@ class VaultTest < ActiveSupport::TestCase
assert_match /no such alias/, err.message
end

test "#config_user creates valid entity" do
@client.config_user(@identity)
entity = @client.read_entity(@identity.sub)
assert entity.data[:policies].any? { |p|
p == @client::Certificate::GENERIC_CERT_POLICY_NAME }
assert entity.data[:aliases].any? { |a|
a[:mount_type] == "oidc" && a[:name] == @identity.sub }
end

private

def vault_client
Expand Down

0 comments on commit e575cab

Please sign in to comment.