From 5b959eb70511e448ddc31485a7c17a32626c0852 Mon Sep 17 00:00:00 2001 From: Alexander Lais Date: Tue, 5 Sep 2023 10:29:46 +0200 Subject: [PATCH 1/6] feat(gorouter): add mTLS client cert metadata verification --- src/code.cloudfoundry.org/gorouter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code.cloudfoundry.org/gorouter b/src/code.cloudfoundry.org/gorouter index 7ae1d87e5..ee4861e41 160000 --- a/src/code.cloudfoundry.org/gorouter +++ b/src/code.cloudfoundry.org/gorouter @@ -1 +1 @@ -Subproject commit 7ae1d87e53b3d07d381d11c3eb8d5dc8fd9e6489 +Subproject commit ee4861e41bc94143433eb823bf83454c21facce8 From 88405b08ad375534326694a59119d24ccd8f95f7 Mon Sep 17 00:00:00 2001 From: Soha Alboghdady Date: Tue, 26 Sep 2023 15:36:35 +0200 Subject: [PATCH 2/6] feat: add verify_client_certificate_metadata to gorouter spec (WIP) --- jobs/gorouter/spec | 15 +++++++++++++++ jobs/gorouter/templates/gorouter.yml.erb | 3 +++ 2 files changed, 18 insertions(+) diff --git a/jobs/gorouter/spec b/jobs/gorouter/spec index 2bb394e9f..dc4c3845a 100644 --- a/jobs/gorouter/spec +++ b/jobs/gorouter/spec @@ -518,6 +518,21 @@ properties: description: "The number of file descriptors a router can have open at one time" default: 100000 + router.verify_client_certificate_metadata: + description: | + Additional client certificate verification which limits the allowed client certificate for given to a signing CA (identified by its subject) to the certificates with subjects provided in the list of valid subjects. Each list entry contains a ca_subject with a coresponding list of valid subjects. + - ca_subject: + - common_name: "" + organization: [] + locality: [] + country: [] + valid_subjects: + - common_name: "" + organizational_units: [] + organizations: [] + locality: [] + country: [] + default: [] healthchecker.failure_counter_file: description: "File used by the healthchecker to monitor consecutive failures." default: /var/vcap/data/gorouter/counters/consecutive_healthchecker_failures.count diff --git a/jobs/gorouter/templates/gorouter.yml.erb b/jobs/gorouter/templates/gorouter.yml.erb index ae8c9c074..5d6a40b71 100644 --- a/jobs/gorouter/templates/gorouter.yml.erb +++ b/jobs/gorouter/templates/gorouter.yml.erb @@ -115,6 +115,7 @@ params = { 'send_http_start_stop_server_event' => p('router.send_http_start_stop_server_event'), 'send_http_start_stop_client_event' => p("router.send_http_start_stop_client_event"), 'empty_pool_timeout' => p('for_backwards_compatibility_only.empty_pool_timeout'), + 'verify_client_certificate_metadata'=> p('router.verify_client_certificate_metadata') } if_p('router.prometheus.port') do |port| @@ -422,5 +423,7 @@ if_p('router.html_error_template') do |t| params['html_error_template_file'] = t == '' ? nil : '/var/vcap/jobs/gorouter/config/error.html' end + + params.to_yaml[3..-1] %> From 98267c9713348bc36c0c1649da7f678c8f1fbf54 Mon Sep 17 00:00:00 2001 From: Alexander Lais Date: Fri, 29 Sep 2023 16:29:03 +0200 Subject: [PATCH 3/6] feat: add check for client cert metadata rules at templating time --- Gemfile | 2 + Gemfile.lock | 2 + jobs/gorouter/spec | 4 ++ jobs/gorouter/templates/gorouter.yml.erb | 63 +++++++++++++++++- packages/gorouter/spec | 17 +++++ spec/gorouter_templates_spec.rb | 83 ++++++++++++++++++++++++ src/code.cloudfoundry.org/gorouter | 2 +- 7 files changed, 170 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index d78e34991..08a8a9eea 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,7 @@ source 'https://rubygems.org' +gem 'openssl' + group :test do gem 'bosh-template' gem 'rspec' diff --git a/Gemfile.lock b/Gemfile.lock index 3f8d7ebde..228766c19 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,7 @@ GEM semi_semantic (~> 1.2.0) diff-lcs (1.3) json (2.6.2) + openssl (3.2.0) parallel (1.22.1) parser (3.1.2.1) ast (~> 2.4.1) @@ -46,6 +47,7 @@ PLATFORMS DEPENDENCIES bosh-template + openssl rspec rubocop diff --git a/jobs/gorouter/spec b/jobs/gorouter/spec index dc4c3845a..4391a94f1 100644 --- a/jobs/gorouter/spec +++ b/jobs/gorouter/spec @@ -518,6 +518,10 @@ properties: description: "The number of file descriptors a router can have open at one time" default: 100000 + router.enable_verify_client_certificate_metadata: + description: | + Enable additional client certificate verification via verify_client_certificate_metadata (see below). + default: false router.verify_client_certificate_metadata: description: | Additional client certificate verification which limits the allowed client certificate for given to a signing CA (identified by its subject) to the certificates with subjects provided in the list of valid subjects. Each list entry contains a ca_subject with a coresponding list of valid subjects. diff --git a/jobs/gorouter/templates/gorouter.yml.erb b/jobs/gorouter/templates/gorouter.yml.erb index 5d6a40b71..5d546129d 100644 --- a/jobs/gorouter/templates/gorouter.yml.erb +++ b/jobs/gorouter/templates/gorouter.yml.erb @@ -1,4 +1,4 @@ ---- +<% require "openssl" %>--- <%= def property_or_link(description, property, link_path, link_name=nil, optional=false) link_name ||= link_path.split('.').first @@ -115,7 +115,6 @@ params = { 'send_http_start_stop_server_event' => p('router.send_http_start_stop_server_event'), 'send_http_start_stop_client_event' => p("router.send_http_start_stop_client_event"), 'empty_pool_timeout' => p('for_backwards_compatibility_only.empty_pool_timeout'), - 'verify_client_certificate_metadata'=> p('router.verify_client_certificate_metadata') } if_p('router.prometheus.port') do |port| @@ -423,7 +422,67 @@ if_p('router.html_error_template') do |t| params['html_error_template_file'] = t == '' ? nil : '/var/vcap/jobs/gorouter/config/error.html' end +# Verification check for client certificate metadata. Only enabled if client_ca_certs +if_p('router.enable_verify_client_certificate_metadata', 'router.verify_client_certificate_metadata', 'router.client_ca_certs') do |enable, rules, client_ca_certs| + if enable and rules.length > 0 then + # Check consistency between client_ca_certs and rules. + + # Find pems in `client_ca_certs`, raise an error if none are defined. + pems = client_ca_certs.scan(/(-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----)/m) + raise "client certificate rules defined, but no client CA defined in `client_ca_certs`" unless pems.length > 0 + + field_map = { + 'common_name' => 'CN', + 'serial_number' => 'SN', + 'organization' => 'O', + 'organization_name' => 'ON', + 'locality' => 'L', + 'country' => 'C', + 'province' => 'ST', + 'street_address' => 'STREET', + } + + # convert the ca_subject of each rule to a X.509 name with its fields sorted alphabetically. + rule_subjects = rules.map { |rule| + fields = [] + # convert properties to X.509 DN field names. Multi-value fields create a tuple for each entry. + rule['ca_subject'].each { |k, v| + mapping = field_map[k] + if v.kind_of?(Array) + v.each { |val| fields.push [ mapping, val] } + else + fields.push [ mapping, v ] + end + } + + # fields are sorted for the configuration and the subject name of the certificate. + sorted_fields = fields.sort{|a,b|a[0] <=> b[0]} + OpenSSL::X509::Name.new sorted_fields + } + + # Get the client CA certificates' subject names in the same alphabetical order as from the configuration. + cert_subjects = pems.map { |pem| + cert = OpenSSL::X509::Certificate.new pem[0] + sorted_fields = cert.subject.to_a.sort{|a,b|a[0] <=> b[0]} + OpenSSL::X509::Name.new sorted_fields + } + + # Check for each of the rules if there is _at least one_ client CA certificate with the same subject. + # Raise an error if there isn't and show which client CA subjects _are_ configured. + rule_subjects.each{ |rule| + unless [rule].intersect?(cert_subjects) then + raise <<~EOF + no CA certificate subjects in `client_ca_certs` matches the rule's subject: #{rule}. \ + `ca_client_certs` subjects: #{cert_subjects.map { |c| c.to_s }.join(", ")}" + EOF + end + } + # now that consistency is checked, assign the values. + params['enable_verify_client_certificate_metadata'] = enable + params['verify_client_certificate_metadata'] = rules + end +end params.to_yaml[3..-1] %> diff --git a/packages/gorouter/spec b/packages/gorouter/spec index a58d4ad67..2a3070996 100644 --- a/packages/gorouter/spec +++ b/packages/gorouter/spec @@ -75,6 +75,9 @@ files: - code.cloudfoundry.org/routing-api/trace/*.go # gosub - code.cloudfoundry.org/routing-api/uaaclient/*.go # gosub - code.cloudfoundry.org/vendor/code.cloudfoundry.org/tlsconfig/*.go # gosub + - code.cloudfoundry.org/vendor/filippo.io/edwards25519/*.go # gosub + - code.cloudfoundry.org/vendor/filippo.io/edwards25519/field/*.go # gosub + - code.cloudfoundry.org/vendor/filippo.io/edwards25519/field/*.s # gosub - code.cloudfoundry.org/vendor/github.com/armon/go-proxyproto/*.go # gosub - code.cloudfoundry.org/vendor/github.com/beorn7/perks/quantile/*.go # gosub - code.cloudfoundry.org/vendor/github.com/bmizerany/pat/*.go # gosub @@ -192,8 +195,19 @@ files: - code.cloudfoundry.org/vendor/github.com/vmihailenco/tagparser/v2/*.go # gosub - code.cloudfoundry.org/vendor/github.com/vmihailenco/tagparser/v2/internal/*.go # gosub - code.cloudfoundry.org/vendor/github.com/vmihailenco/tagparser/v2/internal/parser/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/fingerprint/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/internal/bcrypt_pbkdf/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/internal/emoji/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/internal/utils/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/keyutil/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/pemutil/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/randutil/*.go # gosub + - code.cloudfoundry.org/vendor/go.step.sm/crypto/x25519/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/blake2b/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/blake2b/*.s # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/blowfish/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/chacha20/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/chacha20/*.s # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/curve25519/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/ed25519/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/internal/alias/*.go # gosub @@ -204,6 +218,9 @@ files: - code.cloudfoundry.org/vendor/golang.org/x/crypto/pbkdf2/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/salsa20/salsa/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/crypto/salsa20/salsa/*.s # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/scrypt/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/ssh/*.go # gosub + - code.cloudfoundry.org/vendor/golang.org/x/crypto/ssh/internal/bcrypt_pbkdf/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/net/context/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/net/html/*.go # gosub - code.cloudfoundry.org/vendor/golang.org/x/net/html/atom/*.go # gosub diff --git a/spec/gorouter_templates_spec.rb b/spec/gorouter_templates_spec.rb index 02df7d6e7..4754e802b 100644 --- a/spec/gorouter_templates_spec.rb +++ b/spec/gorouter_templates_spec.rb @@ -771,6 +771,89 @@ end end end + context 'verify_client_certificate_metadata' do + context 'not enabled but rules provided' do + before do + deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ + { "ca_subject" => { "common_name" => "test.com" }} + ] + end + it 'does not populate the property' do + expect { parsed_yaml }.not_to raise_error + expect(parsed_yaml['enable_verify_client_certificate_metadata']).to eq(nil) + expect(parsed_yaml['verify_client_certificate_metadata']).to eq(nil) + end + end + + context 'enabled but no rules provided' do + before do + deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = false + deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [] + + end + it 'does not populate the property' do + expect { parsed_yaml }.not_to raise_error + expect(parsed_yaml['enable_verify_client_certificate_metadata']).to eq(nil) + expect(parsed_yaml['verify_client_certificate_metadata']).to eq(nil) + end + end + + context 'enabled without configured client_ca_certs' do + before do + deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true + deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ + { "ca_subject" => { "common_name" => "test-with-san.com" }, + "valid_subjects" => [ + {"ca_subject" => { "common_name" => "test.com client cert1" }}, + {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + ] + } + ] + end + it 'fails generating the template as there are metadata verification rules but no client ca certs' do + expect { parsed_yaml }.to raise_error RuntimeError, "client certificate rules defined, but no client CA defined in `client_ca_certs`" + end + end + context 'enabled with configured client_ca_certs' do + before do + deployment_manifest_fragment['router']['client_ca_certs'] = TEST_CERT + end + context 'and matching rule' do + before do + deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true + deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ + { "ca_subject" => { "common_name" => "test-with-san.com" }, + "valid_subjects" => [ + {"ca_subject" => { "common_name" => "test.com client cert1" }}, + {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + ] + } + ] + end + it 'populates the properties after a successful check' do + expect { parsed_yaml }.not_to raise_error + expect(parsed_yaml['enable_verify_client_certificate_metadata']).to eq(true) + expect(parsed_yaml['verify_client_certificate_metadata']).to eq(deployment_manifest_fragment['router']['verify_client_certificate_metadata']) + end + end + context 'and not matching rule' do + before do + deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true + deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ + { "ca_subject" => { "common_name" => "test-with-san.com", "country" => ["US"] }, + "valid_subjects" => [ + {"ca_subject" => { "common_name" => "test.com client cert1" }}, + {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + ] + } + ] + end + it 'fails and explains the validpopulates the properties after a successful check' do + expect { parsed_yaml }.to raise_error RuntimeError, /no CA certificate subjects in `client_ca_certs` matches the rule's subject:/ + end + end + end + end end # ca_certs, private_key, cert_chain diff --git a/src/code.cloudfoundry.org/gorouter b/src/code.cloudfoundry.org/gorouter index ee4861e41..683ebaa7f 160000 --- a/src/code.cloudfoundry.org/gorouter +++ b/src/code.cloudfoundry.org/gorouter @@ -1 +1 @@ -Subproject commit ee4861e41bc94143433eb823bf83454c21facce8 +Subproject commit 683ebaa7f4466d4140ddd15b09fe1bfd1c217e67 From 308e2ecd4c807f8fd4f892d17572bf3d5a014e30 Mon Sep 17 00:00:00 2001 From: Alexander Lais Date: Mon, 9 Oct 2023 16:39:56 +0200 Subject: [PATCH 4/6] docs: Address review feedback --- jobs/gorouter/spec | 27 +++++++++++++++++++-------- src/code.cloudfoundry.org/gorouter | 2 +- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/jobs/gorouter/spec b/jobs/gorouter/spec index 4391a94f1..7e9439696 100644 --- a/jobs/gorouter/spec +++ b/jobs/gorouter/spec @@ -524,18 +524,29 @@ properties: default: false router.verify_client_certificate_metadata: description: | - Additional client certificate verification which limits the allowed client certificate for given to a signing CA (identified by its subject) to the certificates with subjects provided in the list of valid subjects. Each list entry contains a ca_subject with a coresponding list of valid subjects. + Additional client certificate verification, after the certificate was validated using the regular mTLS mechanism and is issued using one of the CAs in `client_ca_certs`. + The additional verification limits the allowed client certificates for a given signing CA (identified by its subject) to certificates with subjects provided in the list of valid subjects. Within the certificate chain there may be more than one CA certificates (e.g. intermediate CA certificates). The `ca_subject` must match one of the CA certificates in the chain. + Each list entry contains a ca_subject with a corresponding list of valid subjects. Each ca_subject must match one of the certificates in `client_ca_certs`. When a ca_subject is defined that does not match, this raises an error during templating time and at startup in gorouter. - ca_subject: - - common_name: "" - organization: [] - locality: [] - country: [] + common_name: "" + serial_number: "" + country: [] + organisation: [] + organisation_unit: [] + locality: [] + province: [] + street_address: [] + postal_code: [] valid_subjects: - common_name: "" - organizational_units: [] - organizations: [] - locality: [] + serial_number: "" country: [] + organisation: [] + organisation_unit: [] + locality: [] + province: [] + street_address: [] + postal_code: [] default: [] healthchecker.failure_counter_file: description: "File used by the healthchecker to monitor consecutive failures." diff --git a/src/code.cloudfoundry.org/gorouter b/src/code.cloudfoundry.org/gorouter index 683ebaa7f..8ecf760cd 160000 --- a/src/code.cloudfoundry.org/gorouter +++ b/src/code.cloudfoundry.org/gorouter @@ -1 +1 @@ -Subproject commit 683ebaa7f4466d4140ddd15b09fe1bfd1c217e67 +Subproject commit 8ecf760cdbbad299c5fbc963701cdbf20a59b099 From 85ab0bad8818c29e63baf5de3aabd81f692b5dad Mon Sep 17 00:00:00 2001 From: Alexander Lais Date: Tue, 10 Oct 2023 16:25:48 +0200 Subject: [PATCH 5/6] refactor: rename fields based on review comments --- jobs/gorouter/spec | 8 ++++---- jobs/gorouter/templates/gorouter.yml.erb | 4 ++-- spec/gorouter_templates_spec.rb | 26 ++++++++++++------------ src/code.cloudfoundry.org/gorouter | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/jobs/gorouter/spec b/jobs/gorouter/spec index 7e9439696..2f6dcfc70 100644 --- a/jobs/gorouter/spec +++ b/jobs/gorouter/spec @@ -525,9 +525,9 @@ properties: router.verify_client_certificate_metadata: description: | Additional client certificate verification, after the certificate was validated using the regular mTLS mechanism and is issued using one of the CAs in `client_ca_certs`. - The additional verification limits the allowed client certificates for a given signing CA (identified by its subject) to certificates with subjects provided in the list of valid subjects. Within the certificate chain there may be more than one CA certificates (e.g. intermediate CA certificates). The `ca_subject` must match one of the CA certificates in the chain. - Each list entry contains a ca_subject with a corresponding list of valid subjects. Each ca_subject must match one of the certificates in `client_ca_certs`. When a ca_subject is defined that does not match, this raises an error during templating time and at startup in gorouter. - - ca_subject: + The additional verification limits the allowed client certificates for a given signing CA (identified by its subject) to certificates with subjects provided in the list of valid subjects. Within the certificate chain there may be more than one CA certificates (e.g. intermediate CA certificates). The `issuer_in_chain` must match one of the CA certificates in the chain. + Each list entry contains a issuer_in_chain with a corresponding list of valid subjects. Each issuer_in_chain must match one of the certificates in `client_ca_certs`. When an issuer_in_chain is defined that does not match, this raises an error during templating time and at startup in gorouter. + - issuer_in_chain: common_name: "" serial_number: "" country: [] @@ -537,7 +537,7 @@ properties: province: [] street_address: [] postal_code: [] - valid_subjects: + valid_cert_subjects: - common_name: "" serial_number: "" country: [] diff --git a/jobs/gorouter/templates/gorouter.yml.erb b/jobs/gorouter/templates/gorouter.yml.erb index 5d546129d..eb9e69304 100644 --- a/jobs/gorouter/templates/gorouter.yml.erb +++ b/jobs/gorouter/templates/gorouter.yml.erb @@ -442,11 +442,11 @@ if_p('router.enable_verify_client_certificate_metadata', 'router.verify_client_c 'street_address' => 'STREET', } - # convert the ca_subject of each rule to a X.509 name with its fields sorted alphabetically. + # convert the issuer_in_chain of each rule to a X.509 name with its fields sorted alphabetically. rule_subjects = rules.map { |rule| fields = [] # convert properties to X.509 DN field names. Multi-value fields create a tuple for each entry. - rule['ca_subject'].each { |k, v| + rule['issuer_in_chain'].each { |k, v| mapping = field_map[k] if v.kind_of?(Array) v.each { |val| fields.push [ mapping, val] } diff --git a/spec/gorouter_templates_spec.rb b/spec/gorouter_templates_spec.rb index 4754e802b..19e6dd04e 100644 --- a/spec/gorouter_templates_spec.rb +++ b/spec/gorouter_templates_spec.rb @@ -775,7 +775,7 @@ context 'not enabled but rules provided' do before do deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ - { "ca_subject" => { "common_name" => "test.com" }} + { "issuer_in_chain" => { "common_name" => "test.com" }} ] end it 'does not populate the property' do @@ -802,10 +802,10 @@ before do deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ - { "ca_subject" => { "common_name" => "test-with-san.com" }, - "valid_subjects" => [ - {"ca_subject" => { "common_name" => "test.com client cert1" }}, - {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + { "issuer_in_chain" => { "common_name" => "test-with-san.com" }, + "valid_cert_subjects" => [ + {"issuer_in_chain" => { "common_name" => "test.com client cert1" }}, + {"issuer_in_chain" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} ] } ] @@ -822,10 +822,10 @@ before do deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ - { "ca_subject" => { "common_name" => "test-with-san.com" }, - "valid_subjects" => [ - {"ca_subject" => { "common_name" => "test.com client cert1" }}, - {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + { "issuer_in_chain" => { "common_name" => "test-with-san.com" }, + "valid_cert_subjects" => [ + {"issuer_in_chain" => { "common_name" => "test.com client cert1" }}, + {"issuer_in_chain" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} ] } ] @@ -840,10 +840,10 @@ before do deployment_manifest_fragment['router']['enable_verify_client_certificate_metadata'] = true deployment_manifest_fragment['router']['verify_client_certificate_metadata'] = [ - { "ca_subject" => { "common_name" => "test-with-san.com", "country" => ["US"] }, - "valid_subjects" => [ - {"ca_subject" => { "common_name" => "test.com client cert1" }}, - {"ca_subject" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} + { "issuer_in_chain" => { "common_name" => "test-with-san.com", "country" => ["US"] }, + "valid_cert_subjects" => [ + {"issuer_in_chain" => { "common_name" => "test.com client cert1" }}, + {"issuer_in_chain" => { "common_name" => "test.com client cert2", "locality" => ["US"] }} ] } ] diff --git a/src/code.cloudfoundry.org/gorouter b/src/code.cloudfoundry.org/gorouter index 8ecf760cd..cfa2ae5eb 160000 --- a/src/code.cloudfoundry.org/gorouter +++ b/src/code.cloudfoundry.org/gorouter @@ -1 +1 @@ -Subproject commit 8ecf760cdbbad299c5fbc963701cdbf20a59b099 +Subproject commit cfa2ae5eb8c92ff94c68bc716abdf43162732834 From d7885f665f506b97b7584bc3c47a6a49d148b53b Mon Sep 17 00:00:00 2001 From: Alexander Lais Date: Wed, 11 Oct 2023 11:02:47 +0200 Subject: [PATCH 6/6] docs: editorial changes from PR review Co-authored-by: Dominik Froehlich --- jobs/gorouter/spec | 4 ++-- spec/gorouter_templates_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jobs/gorouter/spec b/jobs/gorouter/spec index 2f6dcfc70..2450b817e 100644 --- a/jobs/gorouter/spec +++ b/jobs/gorouter/spec @@ -525,8 +525,8 @@ properties: router.verify_client_certificate_metadata: description: | Additional client certificate verification, after the certificate was validated using the regular mTLS mechanism and is issued using one of the CAs in `client_ca_certs`. - The additional verification limits the allowed client certificates for a given signing CA (identified by its subject) to certificates with subjects provided in the list of valid subjects. Within the certificate chain there may be more than one CA certificates (e.g. intermediate CA certificates). The `issuer_in_chain` must match one of the CA certificates in the chain. - Each list entry contains a issuer_in_chain with a corresponding list of valid subjects. Each issuer_in_chain must match one of the certificates in `client_ca_certs`. When an issuer_in_chain is defined that does not match, this raises an error during templating time and at startup in gorouter. + The additional verification limits the allowed client certificates for a given signing CA (identified by its distinguished name) to certificates with subjects provided in the list of valid subjects. Within the certificate chain there may be more than one CA certificates (e.g. intermediate CA certificates). The `issuer_in_chain` must match one of the CA certificates in the chain. + Each list entry contains an issuer_in_chain with a corresponding list of valid subjects. Each issuer_in_chain must match one of the certificates in `client_ca_certs`. When an issuer_in_chain is defined that does not match, this raises an error during templating time and at startup in gorouter. - issuer_in_chain: common_name: "" serial_number: "" diff --git a/spec/gorouter_templates_spec.rb b/spec/gorouter_templates_spec.rb index 19e6dd04e..d1df2e233 100644 --- a/spec/gorouter_templates_spec.rb +++ b/spec/gorouter_templates_spec.rb @@ -848,7 +848,7 @@ } ] end - it 'fails and explains the validpopulates the properties after a successful check' do + it 'fails and explains the valid cert subjects in the message' do expect { parsed_yaml }.to raise_error RuntimeError, /no CA certificate subjects in `client_ca_certs` matches the rule's subject:/ end end