Skip to content

Commit b677ed9

Browse files
feat: starttls (#558)
Co-authored-by: Ee Durbin <ewdurbin@gmail.com> Co-authored-by: Ee Durbin <ee@python.org>
1 parent 1d63927 commit b677ed9

File tree

6 files changed

+178
-15
lines changed

6 files changed

+178
-15
lines changed

pillar/base/tls.sls

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,80 @@ tls:
6161
svn.psf.io:
6262
roles:
6363
- hg
64+
65+
acme_cert_configs:
66+
67+
bugs.python.org:
68+
validation: http
69+
name: bugs.python.org
70+
roles:
71+
- loadbalancer
72+
- bugs
73+
aliases:
74+
- bugs.jython.org
75+
- issues.roundup-tracker.org
76+
77+
buildbot.python.org:
78+
validation: http
79+
roles:
80+
- loadbalancer
81+
82+
console.python.org:
83+
validation: http
84+
roles:
85+
- loadbalancer
86+
87+
jobs.pyfound.org:
88+
validation: http
89+
roles:
90+
- loadbalancer
91+
92+
jython.org:
93+
validation: http
94+
roles:
95+
- loadbalancer
96+
aliases:
97+
- jython.net
98+
- www.jython.net
99+
- jython.com
100+
- www.jython.com
101+
102+
legacy.python.org:
103+
validation: http
104+
roles:
105+
- loadbalancer
106+
aliases:
107+
- hg.python.org
108+
- svn.python.org
109+
110+
planetpython.org:
111+
validation: http
112+
roles:
113+
- loadbalancer
114+
aliases:
115+
- www.planetpython.org
116+
- planet.python.org
117+
118+
pypa.io:
119+
validation: http
120+
roles:
121+
- loadbalancer
122+
123+
salt-public.psf.io:
124+
validation: http
125+
roles:
126+
- loadbalancer
127+
128+
speed.python.org:
129+
validation: http
130+
roles:
131+
- loadbalancer
132+
aliases:
133+
- speed.pypy.org
134+
135+
wiki.python.org:
136+
validation: http
137+
roles:
138+
- loadbalancer
139+
aliases:
140+
- wiki.jython.org

pillar/dev/top.sls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ base:
88
- tls
99
- users.*
1010
- postgres.clusters
11+
- pebble # needing to do this to have pebble rum in dev
1112
# - secrets.sentry # Uncomment and update sentry secrets if you want to work in dev
1213

1314
'backup-server':

salt/_extensions/pillar/ca.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -295,46 +295,69 @@ def get_ca_signed_cert(cacert_path, ca_name, CN):
295295
return "\n".join([cert, key])
296296

297297

298+
def _read_cert_file(path: str) -> str:
299+
"""Helper to read certificate files, which might be symlinks"""
300+
try:
301+
with open(path, 'r') as f:
302+
return f.read()
303+
except (IOError, OSError):
304+
return None
305+
306+
298307
def ext_pillar(minion_id, pillar, base="/etc/ssl", name="PSFCA", cert_opts=None):
299308
if cert_opts is None:
300309
cert_opts = {}
301310

302-
# Ensure we have a CA created.
311+
# Create CA certificate
303312
opts = cert_opts.copy()
304313
opts["CN"] = name
305314
create_ca(base, name, **opts)
306315

307-
# Start our pillar with just the ca certificate.
308316
data = {
309317
"tls": {
310318
"ca": {
311319
name: get_ca_cert(base, name),
312320
},
313321
"certs": {},
322+
"acme_certs": {},
314323
},
315324
}
316325

317-
# Create all of the certificates required by this minion
326+
minion_roles = []
327+
minion_roles.extend(
328+
role_name
329+
for role_name, role_config in pillar.get("roles", {}).items()
330+
if role_config.get("pattern")
331+
and compound(role_config["pattern"], minion_id)
332+
)
333+
334+
# Process CA-signed certificates (gen_certs)
318335
gen_certs = pillar.get("tls", {}).get("gen_certs", {})
319336
for certificate, config in gen_certs.items():
320-
role_patterns = [
321-
role.get("pattern")
322-
for role in [
323-
pillar.get("roles", {}).get(r) for r in config.get("roles", "")
324-
]
325-
if role and role.get("pattern") is not None
326-
]
327-
if any([compound(pat, minion_id) for pat in role_patterns]):
337+
cert_roles = config.get("roles", [])
338+
# Check if any of the minion's roles are in the certificate's required roles
339+
if any(role in minion_roles for role in cert_roles):
328340
# Create the options
329341
opts = cert_opts.copy()
330342
opts["CN"] = certificate
331343
opts["days"] = config.get("days", 1)
332344

333-
# Create the signed certificates
334345
create_ca_signed_cert(base, name, **opts)
335346

336347
# Add the signed certificates to the pillar data
337348
cert_data = get_ca_signed_cert(base, name, certificate)
338349
data["tls"]["certs"][certificate] = cert_data
339350

340-
return data
351+
# Collect ACME certs (acme.cert) for this minion based on its roles
352+
acme_cert_configs = pillar.get("tls", {}).get("acme_cert_configs", {})
353+
for domain, domain_config in acme_cert_configs.items():
354+
cert_roles = domain_config.get("roles", [])
355+
if any(role in minion_roles for role in cert_roles):
356+
cert_name = domain_config.get('name', domain)
357+
full_cert_chain = _read_cert_file(f"/etc/letsencrypt/live/{cert_name}/fullchain.pem")
358+
privkey = _read_cert_file(f"/etc/letsencrypt/live/{cert_name}/privkey.pem")
359+
360+
if full_cert_chain and privkey:
361+
data["tls"]["acme_certs"][domain] = full_cert_chain + "\n" + privkey
362+
363+
return data

salt/bugs/config/postfix/main.cf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ compatibility_level = 3.6
2424

2525

2626
# TLS parameters
27-
smtpd_tls_cert_file=ssl_certificate /etc/ssl/private/bugs.psf.io.pem;
28-
smtpd_tls_key_file=etc/ssl/private/bugs.psf.io.pem;
27+
smtpd_tls_cert_file=/etc/ssl/private/acme-bugs.python.org.pem
28+
smtpd_tls_key_file=/etc/ssl/private/acme-bugs.python.org.pem
2929
smtpd_tls_security_level=may
3030

3131
smtp_tls_CApath=/etc/ssl/certs

salt/tls/init.sls

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
include:
2+
- .pebble
3+
- .lego
4+
15
ssl-cert:
26
pkg.installed
37

8+
certbot:
9+
pkg.installed
410

511
{% for name in salt["pillar.get"]("tls:ca", {}) %} # " Syntax Hack
612
/etc/ssl/certs/{{ name }}.pem:
@@ -11,8 +17,21 @@ ssl-cert:
1117
- mode: "0644"
1218
- require:
1319
- pkg: ssl-cert
20+
21+
/usr/local/share/ca-certificates/{{ name }}.crt:
22+
file.managed:
23+
- contents_pillar: tls:ca:{{ name }}
24+
- user: root
25+
- group: ssl-cert
26+
- mode: "0644"
27+
- require:
28+
- pkg: ssl-cert
1429
{% endfor %}
1530

31+
/usr/sbin/update-ca-certificates:
32+
cmd.run:
33+
- onchanges:
34+
- file: /usr/local/share/ca-certificates/*.crt
1635

1736
{% for name in salt["pillar.get"]("tls:certs", {}) %} # " Syntax Hack
1837
/etc/ssl/private/{{ name }}.pem:
@@ -25,3 +44,44 @@ ssl-cert:
2544
- require:
2645
- pkg: ssl-cert
2746
{% endfor %}
47+
48+
# Install acme.cert certs prepended with acme-* to avoic conflicts
49+
{% for name in salt["pillar.get"]("tls:acme_certs", {}) %}
50+
/etc/ssl/private/acme-{{ name }}.pem:
51+
file.managed:
52+
- contents_pillar: tls:acme_certs:{{ name }}
53+
- user: root
54+
- group: ssl-cert
55+
- mode: "0640"
56+
- show_diff: False
57+
- require:
58+
- pkg: ssl-cert
59+
{% endfor %}
60+
61+
{% if salt["match.compound"](pillar["roles"]["salt-master"]["pattern"]) %}
62+
# Process ACME certificates
63+
{% for domain, domain_config in salt["pillar.get"]("tls:acme_cert_configs", {}).items() %}
64+
{{ domain }}:
65+
acme.cert:
66+
- email: infrastructure-staff@python.org
67+
- webroot: /etc/lego
68+
- renew: 14
69+
{% if domain_config.get('aliases') %}
70+
- aliases:
71+
{% for alias in domain_config.get('aliases', []) %}
72+
- {{ alias }}
73+
{% endfor %}
74+
{% endif %}
75+
{% if pillar["dc"] == "vagrant" %}
76+
- server: https://salt-master.vagrant.psf.io:14000/dir
77+
{% endif %}
78+
{% if domain_config.get('validation') == "dns" %}
79+
- dns_plugin: {{ domain_config.get('dns_plugin') }}
80+
- dns_plugin_credentials: {{ domain_config.get('dns_plugin_credentials') }}
81+
{% else %}
82+
- require:
83+
- sls: tls.lego
84+
- pkg: certbot
85+
{% endif %}
86+
{% endfor %}
87+
{% endif %}

salt/tls/pebble.sls

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{% if salt["match.compound"](pillar["roles"]["salt-master"]["pattern"]) %}
12
{% if pillar.get('pebble', {'enabled': False}).enabled %}
23
pebble-build-deps:
34
pkg.installed:
@@ -60,3 +61,4 @@ pebble-service:
6061
- file: /etc/ssl/certs/PSF_CA.pem
6162
- file: /etc/ssl/private/salt-master.vagrant.psf.io.pem
6263
{% endif %}
64+
{% endif %}

0 commit comments

Comments
 (0)