Exposing CA keys in a mine creates a security flaw, thus such should be avoided. This change removes code responsible for putting and retrieving CA key from a mine and changes the ca.sls state to allow configuring where CA cert and its key would be generated as well as their owners. Fixes PROD-13439 Change-Id: I6d78b13dcb3754c51606edd7e2d8158e128244a4pull/56/head
{%- from "salt/map.jinja" import minion with context %} | {%- from "salt/map.jinja" import minion with context %} | ||||
x509_signing_policies: | x509_signing_policies: | ||||
{%- for ca_name,ca in minion.ca.items() %} | {%- for ca_name,ca in minion.ca.items() %} | ||||
{%- set ca_file = ca.get('ca_file', '/etc/pki/ca/' ~ ca_name ~ '/ca.crt') %} | |||||
{%- set ca_key_file = ca.get('ca_key_file', '/etc/pki/ca/' ~ ca_name ~ '/ca.key') %} | |||||
{%- set ca_certs_dir = salt['file.dirname'](ca_file) ~ '/certs/' %} | |||||
{%- for signing_policy_name, signing_policy in ca.signing_policy.iteritems() %} | {%- for signing_policy_name, signing_policy in ca.signing_policy.iteritems() %} | ||||
{{ ca_name }}_{{ signing_policy_name }}: | {{ ca_name }}_{{ signing_policy_name }}: | ||||
- minions: '{{ signing_policy.minions }}' | - minions: '{{ signing_policy.minions }}' | ||||
- signing_private_key: /etc/pki/ca/{{ ca_name }}/ca.key | |||||
- signing_cert: /etc/pki/ca/{{ ca_name }}/ca.crt | |||||
- signing_private_key: {{ ca_key_file }} | |||||
- signing_cert: {{ ca_file }} | |||||
{%- if ca.country is defined %} | {%- if ca.country is defined %} | ||||
- C: {{ ca.country }} | - C: {{ ca.country }} | ||||
{%- endif %} | {%- endif %} | ||||
- subjectKeyIdentifier: hash | - subjectKeyIdentifier: hash | ||||
- authorityKeyIdentifier: keyid,issuer:always | - authorityKeyIdentifier: keyid,issuer:always | ||||
- days_valid: {{ ca.days_valid.certificate }} | - days_valid: {{ ca.days_valid.certificate }} | ||||
- copypath: /etc/pki/ca/{{ ca_name }}/certs/ | |||||
- copypath: {{ ca_certs_dir }} | |||||
{%- endfor %} | {%- endfor %} | ||||
{%- endfor %} | {%- endfor %} | ||||
{%- endif %} | {%- endif %} |
{%- for ca_name,ca in minion.ca.iteritems() %} | {%- for ca_name,ca in minion.ca.iteritems() %} | ||||
/etc/pki/ca/{{ ca_name }}/certs: | |||||
{%- set ca_file = ca.get('ca_file', '/etc/pki/ca/' ~ ca_name ~ '/ca.crt') %} | |||||
{%- set ca_key_file = ca.get('ca_key_file', '/etc/pki/ca/' ~ ca_name ~ '/ca.key') %} | |||||
{%- set ca_key_usage = ca.get('key_usage',"critical,cRLSign,keyCertSign") %} | |||||
{%- set ca_dir = salt['file.dirname'](ca_file) %} | |||||
{%- set ca_key_dir = salt['file.dirname'](ca_key_file) %} | |||||
{%- set ca_certs_dir = ca_dir ~ '/certs' %} | |||||
salt_minion_cert_{{ ca_name }}_dirs: | |||||
file.directory: | file.directory: | ||||
- makedirs: true | |||||
- names: | |||||
- {{ ca_dir }} | |||||
- {{ ca_key_dir }} | |||||
- {{ ca_certs_dir }} | |||||
- makedirs: true | |||||
/etc/pki/ca/{{ ca_name }}/ca.key: | |||||
{{ ca_key_file }}: | |||||
x509.private_key_managed: | x509.private_key_managed: | ||||
- bits: 4096 | - bits: 4096 | ||||
- backup: True | - backup: True | ||||
- require: | - require: | ||||
- file: /etc/pki/ca/{{ ca_name }}/certs | |||||
- file: {{ ca_certs_dir }} | |||||
# TODO: Squash this with the previous state after switch to Salt version >= 2016.11.2 | |||||
{{ ca_name }}_key_permissions: | |||||
file.managed: | |||||
- name: {{ ca_key_file }} | |||||
- mode: {{ ca.get("mode", 0600) }} | |||||
{%- if salt['user.info'](ca.get("user", "root")) %} | |||||
- user: {{ ca.get("user", "root") }} | |||||
{%- endif %} | |||||
{%- if salt['group.info'](ca.get("group", "root")) %} | |||||
- group: {{ ca.get("group", "root") }} | |||||
{%- endif %} | |||||
- replace: false | |||||
- require: | |||||
- x509: {{ ca_key_file }} | |||||
/etc/pki/ca/{{ ca_name }}/ca.crt: | |||||
{{ ca_file }}: | |||||
x509.certificate_managed: | x509.certificate_managed: | ||||
- signing_private_key: /etc/pki/ca/{{ ca_name }}/ca.key | |||||
- signing_private_key: {{ ca_key_file }} | |||||
- CN: "{{ ca.common_name }}" | - CN: "{{ ca.common_name }}" | ||||
{%- if ca.country is defined %} | {%- if ca.country is defined %} | ||||
- C: {{ ca.country }} | - C: {{ ca.country }} | ||||
- OU: {{ ca.organization_unit }} | - OU: {{ ca.organization_unit }} | ||||
{%- endif %} | {%- endif %} | ||||
- basicConstraints: "critical,CA:TRUE" | - basicConstraints: "critical,CA:TRUE" | ||||
- keyUsage: "critical,cRLSign,keyCertSign" | |||||
- keyUsage: {{ ca_key_usage }} | |||||
- subjectKeyIdentifier: hash | - subjectKeyIdentifier: hash | ||||
- authorityKeyIdentifier: keyid,issuer:always | - authorityKeyIdentifier: keyid,issuer:always | ||||
- days_valid: {{ ca.days_valid.authority }} | - days_valid: {{ ca.days_valid.authority }} | ||||
- days_remaining: 0 | - days_remaining: 0 | ||||
- backup: True | - backup: True | ||||
- require: | - require: | ||||
- x509: /etc/pki/ca/{{ ca_name }}/ca.key | |||||
- x509: {{ ca_key_file }} | |||||
# TODO: Squash this with the previous state after switch to Salt version >= 2016.11.2 | |||||
{{ ca_name }}_cert_permissions: | |||||
file.managed: | |||||
- name: {{ ca_file }} | |||||
- mode: 0644 | |||||
{%- if salt['user.info'](ca.get("user", "root")) %} | |||||
- user: {{ ca.get("user", "root") }} | |||||
{%- endif %} | |||||
{%- if salt['group.info'](ca.get("group", "root")) %} | |||||
- group: {{ ca.get("group", "root") }} | |||||
{%- endif %} | |||||
- require: | |||||
- x509: {{ ca_file }} | |||||
salt_system_ca_mine_send_ca_{{ ca_name }}: | salt_system_ca_mine_send_ca_{{ ca_name }}: | ||||
module.run: | module.run: | ||||
- name: mine.send | - name: mine.send | ||||
- func: x509.get_pem_entries | - func: x509.get_pem_entries | ||||
- kwargs: | - kwargs: | ||||
glob_path: /etc/pki/ca/{{ ca_name }}/ca.crt | |||||
- require: | |||||
- x509: /etc/pki/ca/{{ ca_name }}/ca.crt | |||||
salt_system_ca_mine_send_ca_key_{{ ca_name }}: | |||||
module.run: | |||||
- name: mine.send | |||||
- func: x509_get_private_key | |||||
- kwargs: | |||||
mine_function: x509.get_pem_entries | |||||
glob_path: /etc/pki/ca/{{ ca_name }}/ca.key | |||||
glob_path: {{ ca_file }} | |||||
- require: | - require: | ||||
- x509: /etc/pki/ca/{{ ca_name }}/ca.key | |||||
- x509: {{ ca_file }} | |||||
{%- endfor %} | {%- endfor %} | ||||
{%- if minion.cert is defined %} | {%- if minion.cert is defined %} | ||||
{%- set created_ca_files = [] %} | {%- set created_ca_files = [] %} | ||||
{%- set created_ca_key_files = [] %} | |||||
{%- for cert_name,cert in minion.get('cert', {}).iteritems() %} | {%- for cert_name,cert in minion.get('cert', {}).iteritems() %} | ||||
{%- set rowloop = loop %} | {%- set rowloop = loop %} | ||||
{%- set key_file = cert.get('key_file', '/etc/ssl/private/' + cert.common_name + '.key') %} | {%- set key_file = cert.get('key_file', '/etc/ssl/private/' + cert.common_name + '.key') %} | ||||
{%- set cert_file = cert.get('cert_file', '/etc/ssl/certs/' + cert.common_name + '.crt') %} | {%- set cert_file = cert.get('cert_file', '/etc/ssl/certs/' + cert.common_name + '.crt') %} | ||||
{%- set ca_file = cert.get('ca_file', '/etc/ssl/certs/ca-' + cert.authority + '.crt') %} | {%- set ca_file = cert.get('ca_file', '/etc/ssl/certs/ca-' + cert.authority + '.crt') %} | ||||
{%- set ca_key_file = cert.get('ca_key_file', '/etc/ssl/certs/ca-' + cert.authority + '.key') %} | |||||
{%- set key_dir = salt['file.dirname'](key_file) %} | {%- set key_dir = salt['file.dirname'](key_file) %} | ||||
{%- set cert_dir = salt['file.dirname'](cert_file) %} | {%- set cert_dir = salt['file.dirname'](cert_file) %} | ||||
{%- set ca_dir = salt['file.dirname'](ca_file) %} | {%- set ca_dir = salt['file.dirname'](ca_file) %} | ||||
{%- set ca_key_dir = salt['file.dirname'](ca_key_file) %} | |||||
{# Only ensure directories exists, don't touch permissions, etc. #} | {# Only ensure directories exists, don't touch permissions, etc. #} | ||||
salt_minion_cert_{{ cert_name }}_dirs: | salt_minion_cert_{{ cert_name }}_dirs: | ||||
- {{ key_dir }} | - {{ key_dir }} | ||||
- {{ cert_dir }} | - {{ cert_dir }} | ||||
- {{ ca_dir }} | - {{ ca_dir }} | ||||
- {{ ca_key_dir }} | |||||
- makedirs: true | - makedirs: true | ||||
- replace: false | - replace: false | ||||
- cmd: salt_minion_cert_{{ cert_name }}_all | - cmd: salt_minion_cert_{{ cert_name }}_all | ||||
{%- endif %} | {%- endif %} | ||||
# TODO: Squash this with the previous state after switch to Salt version >= 2016.11.2 | |||||
{{ key_file }}_key_permissions: | {{ key_file }}_key_permissions: | ||||
file.managed: | file.managed: | ||||
- name: {{ key_file }} | - name: {{ key_file }} | ||||
- group: {{ cert.get("group", "root") }} | - group: {{ cert.get("group", "root") }} | ||||
{%- endif %} | {%- endif %} | ||||
- replace: false | - replace: false | ||||
- watch: | |||||
- require: | |||||
- x509: {{ key_file }} | - x509: {{ key_file }} | ||||
{{ cert_file }}: | {{ cert_file }}: | ||||
- cmd: salt_minion_cert_{{ cert_name }}_all | - cmd: salt_minion_cert_{{ cert_name }}_all | ||||
{%- endif %} | {%- endif %} | ||||
# TODO: Squash this with the previous state after switch to Salt version >= 2016.11.2 | |||||
{{ cert_file }}_cert_permissions: | {{ cert_file }}_cert_permissions: | ||||
file.managed: | file.managed: | ||||
- name: {{ cert_file }} | - name: {{ cert_file }} | ||||
- group: {{ cert.get("group", "root") }} | - group: {{ cert.get("group", "root") }} | ||||
{%- endif %} | {%- endif %} | ||||
- replace: false | - replace: false | ||||
- watch: | |||||
- require: | |||||
- x509: {{ cert_file }} | - x509: {{ cert_file }} | ||||
{%- if cert.host is defined and ca_file not in created_ca_files %} | {%- if cert.host is defined and ca_file not in created_ca_files %} | ||||
{%- endif %} | {%- endif %} | ||||
# TODO: Squash this with the previous state after switch to Salt version >= 2016.11.2 | |||||
{{ ca_file }}_cert_permissions: | {{ ca_file }}_cert_permissions: | ||||
file.managed: | file.managed: | ||||
- name: {{ ca_file }} | - name: {{ ca_file }} | ||||
{%- if salt['group.info'](cert.get("group", "root")) %} | {%- if salt['group.info'](cert.get("group", "root")) %} | ||||
- group: {{ cert.get("group", "root") }} | - group: {{ cert.get("group", "root") }} | ||||
{%- endif %} | {%- endif %} | ||||
- watch: | |||||
- require: | |||||
- x509: {{ ca_file }} | - x509: {{ ca_file }} | ||||
{%- endif %} | {%- endif %} | ||||
{%- do created_ca_files.append(ca_file) %} | {%- do created_ca_files.append(ca_file) %} | ||||
{%- endif %} | {%- endif %} | ||||
{%- if cert.host is defined and ca_key_file not in created_ca_key_files %} | |||||
{%- for ca_key_path,ca_key in salt['mine.get'](cert.host, 'x509_get_private_key').get(cert.host, {}).iteritems() %} | |||||
{%- if '/etc/pki/ca/'+cert.authority in ca_key_path %} | |||||
{{ ca_key_file }}: | |||||
x509.pem_managed: | |||||
- name: {{ ca_key_file }} | |||||
- text: {{ ca_key|replace('\n', '') }} | |||||
- watch: | |||||
- x509: {{ cert_file }} | |||||
{{ ca_key_file }}_cert_permissions: | |||||
file.managed: | |||||
- name: {{ ca_key_file }} | |||||
- mode: 0644 | |||||
{%- if salt['user.info'](cert.get("user", "root")) %} | |||||
- user: {{ cert.get("user", "root") }} | |||||
{%- endif %} | |||||
{%- if salt['group.info'](cert.get("group", "root")) %} | |||||
- group: {{ cert.get("group", "root") }} | |||||
{%- endif %} | |||||
- watch: | |||||
- x509: {{ ca_key_file }} | |||||
{%- endif %} | |||||
{%- endfor %} | |||||
{%- do created_ca_key_files.append(ca_key_file) %} | |||||
{%- endif %} | |||||
{%- if cert.all_file is defined %} | {%- if cert.all_file is defined %} | ||||
salt_minion_cert_{{ cert_name }}_all: | salt_minion_cert_{{ cert_name }}_all: | ||||
- group: {{ cert.get("group", "root") }} | - group: {{ cert.get("group", "root") }} | ||||
{%- endif %} | {%- endif %} | ||||
- replace: false | - replace: false | ||||
- watch: | |||||
- require: | |||||
- cmd: salt_minion_cert_{{ cert_name }}_all | - cmd: salt_minion_cert_{{ cert_name }}_all | ||||
{%- endif %} | {%- endif %} | ||||
{%- for trusted_ca_minion in minion.get('trusted_ca_minions', []) %} | {%- for trusted_ca_minion in minion.get('trusted_ca_minions', []) %} | ||||
{%- for ca_host, certs in salt['mine.get'](trusted_ca_minion+'*', 'x509.get_pem_entries').iteritems() %} | {%- for ca_host, certs in salt['mine.get'](trusted_ca_minion+'*', 'x509.get_pem_entries').iteritems() %} | ||||
{%- for ca_path, ca_cert in certs.iteritems() %} | {%- for ca_path, ca_cert in certs.iteritems() %} | ||||
{%- if ca_path.startswith('/etc/pki/ca/') and ca_path.endswith('ca.crt') %} | |||||
{%- if ca_path.endswith('ca.crt') %} | |||||
{# authority name can be obtained only from a cacert path in case of mine.get #} | {# authority name can be obtained only from a cacert path in case of mine.get #} | ||||
{%- set ca_authority = ca_path.split("/")[4] %} | |||||
{%- set ca_authority = ca_path.split("/")[-2] %} | |||||
{%- set cacert_file="%s/ca-%s.crt" % (cacerts_dir,ca_authority) %} | {%- set cacert_file="%s/ca-%s.crt" % (cacerts_dir,ca_authority) %} | ||||
salt_trust_ca_{{ cacert_file }}: | salt_trust_ca_{{ cacert_file }}: |
ca_intermediate: | ca_intermediate: | ||||
type: v3_intermediate_ca | type: v3_intermediate_ca | ||||
minions: '*' | minions: '*' | ||||
salt-ca-alt: | |||||
common_name: Alt CA Testing | |||||
country: Czech | |||||
state: Prague | |||||
locality: Cesky Krumlov | |||||
days_valid: | |||||
authority: 3650 | |||||
certificate: 90 | |||||
signing_policy: | |||||
cert_server: | |||||
type: v3_edge_cert_server | |||||
minions: '*' | |||||
cert_client: | |||||
type: v3_edge_cert_client | |||||
minions: '*' | |||||
ca_edge: | |||||
type: v3_edge_ca | |||||
minions: '*' | |||||
ca_intermediate: | |||||
type: v3_intermediate_ca | |||||
minions: '*' | |||||
ca_file: '/etc/test/ca.crt' | |||||
ca_key_file: '/etc/test/ca.key' | |||||
user: test | |||||
group: test |
# salt.ci.local | # salt.ci.local | ||||
#signing_policy: | #signing_policy: | ||||
# cert_server | # cert_server | ||||
test_cert: | |||||
alternative_names: | |||||
IP:127.0.0.1,DNS:salt.ci.local,DNS:test.ci.local | |||||
cert_file: | |||||
/srv/salt/pki/ci/test.ci.local.crt | |||||
common_name: | |||||
test.ci.local | |||||
key_file: | |||||
/srv/salt/pki/ci/test.ci.local.key | |||||
country: CZ | |||||
state: Prague | |||||
locality: Cesky Krumlov | |||||
signing_cert: | |||||
/etc/test/ca.crt | |||||
signing_private_key: | |||||
/etc/test/ca.key | |||||
# Kitchen-Salt CI trigger `salt-call --local`, below attributes | |||||
# can't be used as there is no required SaltMaster connectivity | |||||
authority: | |||||
salt-ca-alt |