Skip to content

Commit bd1eab2

Browse files
Merge pull request #400 from pulibrary/i171_tls_certs
we can automate management of TLS certs
2 parents 8571549 + 29fc84c commit bd1eab2

File tree

2 files changed

+205
-209
lines changed

2 files changed

+205
-209
lines changed

services/create_ssl_certs.md

Lines changed: 74 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
1. If the certificate already exists you will need to revoke it before running your chosen playbook
1010

1111
### For sites outside the Princeton domain
12-
1. Create the CSR (certificate signing request) - can be automated with [playbooks/cert_renewal.yml](https://github.com/pulibrary/princeton_ansible/blob/main/playbooks/incommon_certbot.yml)
13-
2. Submit it to gandi via [this form](https://shop.gandi.net/en/certificate/create)
14-
3. Your TLS/SSL cert will be created and returned to you via a email within 3 hours from gandi.net
12+
1. Create a new entry under [sites](https://github.com/pulibrary/princeton_ansible/blob/dac77a6c2e0f1301201c9b2a63b9ebead5f7b7ac/group_vars/nginxplus/production.yml#L16)
13+
2. Run the [nginxplus playbook](https://github.com/pulibrary/princeton_ansible/blob/main/playbooks/nginxplus.yml)
14+
3. Your TLS/SSL cert will be on the production loadbalancer
1515
4. Verify the files you get back and add them to your server configuration.
1616

1717
## Verifying certbot certificate renewals
@@ -28,244 +28,109 @@ Our certificate management system is Sectigo. Operations folks can [log into Sec
2828

2929
These certs are not managed by our usual process. These certs cover:
3030
- sites we do not serve from the load balancers
31-
- sites without the '.princeton.edu' extension
3231
- vendor-hosted sites with the '.princeton.edu' extension
3332
Many of these certs must be deployed manually. Some must also be renewed manually. If a private key is kept in princeton_ansible, it is encrypted as a file in the `/keys/` directory of the repo.
3433

35-
cicognara.org
36-
Purpose: public site for the Cicognara collection (a collaborative project)
37-
Managed: on gandi.net, private key is in princeton_ansible
38-
Deployed: on the load balancers
34+
cicognara.org
35+
Purpose: public site for the Cicognara collection (a collaborative project)
36+
Managed: [Lego](https://github.com/pulibrary/princeton_ansible/blob/main/roles/nginxplus/tasks/lego.yml)
37+
Deployed: on the load balancers
3938

4039
dataspace.princeton.edu
40+
Purpose: production site for dspace
41+
Managed: Via [Lego](lego.md)
42+
Deployed: on Google cloud, on prod.pulcloud.io
4143

42-
dataspace-dev.princeton.edu
43-
Purpose: dev/staging site for dspace
44-
Managed: in ServiceNow, private key is on princeton_ansible
45-
Deployed: on Google cloud, on dev.pulcloud.io
44+
dataspace-dev.princeton.edu
45+
Purpose: dev/staging site for dspace
46+
Managed: Via [Lego](lego.md)
47+
Deployed: on Google cloud, on dev.pulcloud.io
4648

4749
dataspace-staging.princeton.edu
48-
49-
dss2.princeton.edu
50-
Purpose: secures dataset downloads from a separate server for DSS via a web browser
51-
Managed: in ServiceNow - John will move to letsencrypt
52-
Deployed: on the dss2 CentOS VM
50+
Purpose: dev/staging site for dspace
51+
Managed: Via [Lego](lego.md)
52+
Deployed: on Google cloud, on dev.pulcloud.io
53+
54+
dss2.princeton.edu
55+
Purpose: secures dataset downloads from a separate server for DSS via a web browser
56+
Managed: in ServiceNow - John will move to letsencrypt
57+
Deployed: on the dss2 CentOS VM
5358
Notes: cannot be a SAN name for the main DSS cert, because we only want to secure this functionality on one machine - can be tricky to maintain because server access requires signing nondisclosure agreements (for protected data)
5459

55-
ezproxy.princeton.edu
56-
Purpose: allows access to journals by confirming Princeton affiliation
57-
Managed: on ezproxy-prod1 by letsencrypt
58-
Deployed: in /etc/letsencrypt/live/ezproxy on the ezproxy-prod1 server
60+
ezproxy.princeton.edu
61+
Purpose: allows access to journals by confirming Princeton affiliation
62+
Managed: on ezproxy-prod1 by letsencrypt
63+
Deployed: in /etc/letsencrypt/live/ezproxy on the ezproxy-prod1 server
5964

60-
imagecat2.princeton.edu
65+
imagecat2.princeton.edu
6166
Philippe will shut down the server once he has copied whatever we need from it. Once it's gone, we can revoke the cert.
6267

63-
lib-aeon.princeton.edu
64-
Purpose: redirects traffic to hosted Aeon service at https://princeton.aeon.atlas-sys.com
65-
Managed: for new site by the vendor
66-
Deployed: to new site by the vendor
68+
lib-aeon.princeton.edu
69+
Purpose: redirects traffic to hosted Aeon service at https://princeton.aeon.atlas-sys.com
70+
Managed: for new site by the vendor
71+
Deployed: to new site by the vendor
6772
Notes: We would like to redirect the old URL on the load balancers and power off the old lib-aeon machine. The templates for printing Aeon call slips, which used to live on the lib-aeon machine, have been moved to a fileshare called aeonprint on lib-fileshare.
6873

69-
lib-gisportal.princeton.edu
70-
Purpose: for maps (Wangyal)
71-
Managed: in ServiceNow
72-
Deployed: in IIS on a physical machine that runs MS HyperV virtualization - cluster of lib-geoserv1 and lib-geoserv2 (not the Lib-Gisportal2 VM) server
74+
lib-gisportal.princeton.edu
75+
Purpose: for maps (Wangyal)
76+
Managed: in ServiceNow
77+
Deployed: in IIS on a physical machine that runs MS HyperV virtualization - cluster of lib-geoserv1 and lib-geoserv2 (not the Lib-Gisportal2 VM) server
7378
Notes: windows physical machine, you must be an admin on the Windows box, expires 2024/07/30
7479

75-
lib-illsql.princeton.edu
76-
Purpose: interlibrary loan
77-
Managed: in ServiceNow
78-
Deployed: in IIS, on the lib-illiad-new VM
80+
lib-illsql.princeton.edu
81+
Purpose: interlibrary loan
82+
Managed: in ServiceNow
83+
Deployed: in IIS, on the lib-illiad-new VM
7984
Notes: Windows VM; cert has a SAN name of lib-illiad.princeton.edu; we hope to migrate this to a hosted platform in 2024
8085

81-
libserv97.princeton.edu
82-
Purpose: Philippe's test machine, may disappear in 2024
83-
Managed: in ServiceNow
86+
libserv97.princeton.edu
87+
Purpose: Philippe's test machine, may disappear in 2024
88+
Managed: in ServiceNow
8489
Deployed: directly on the libserv97 VM (dev environment)
8590

8691
oar.princeton.edu
87-
88-
oar-dev.princeton.edu
89-
Purpose: open access repository
90-
Managed: in ServiceNow, private key is on princeton_ansible
91-
Deployed: on Google cloud at dev.pulcloud.io
92-
93-
oar-staging.princeton.edu
94-
Purpose: open access repository
95-
Managed: in ServiceNow, private key is on princeton_ansible
96-
Deployed: on Google cloud at staging.pulcloud.io
97-
98-
pulmirror.princeton.edu
99-
Purpose: distributing Ubuntu packages
100-
Managed: in ServiceNow, private key is in princeton_ansible
92+
Purpose: production site for oar
93+
Managed: Via [Lego](lego.md)
94+
Deployed: on Google cloud, on prod.pulcloud.io
95+
96+
oar-dev.princeton.edu
97+
Purpose: production site for oar
98+
Managed: Via [Lego](lego.md)
99+
Deployed: on Google cloud, on prod.pulcloud.io
100+
101+
oar-staging.princeton.edu
102+
Purpose: production site for oar
103+
Managed: Via [Lego](lego.md)
104+
Deployed: on Google cloud, on prod.pulcloud.io
105+
106+
pcdm.org
107+
Purpose: Portland Common Data Model
108+
Managed: [Lego](https://github.com/pulibrary/princeton_ansible/blob/main/roles/nginxplus/tasks/lego.yml)
109+
110+
pulmirror.princeton.edu
111+
Purpose: distributing Ubuntu packages
112+
Managed: Via [Lego](lego.md)
101113
Deployed: on Google cloud at pulmirror.princeton.edu
102114

103-
recapgfa.princeton.edu
104-
Purpose: ReCAP inventory management system
105-
Managed: by ACME directly on the VM
115+
recapgfa.princeton.edu
116+
Purpose: ReCAP inventory management system
117+
Managed: by ACME directly on the VM
106118
Deployed: N/A - it automatically renews
107119

108-
simrisk.pulcloud.io
109-
Purpose: experimental application for CDH
110-
Managed: on staging.pulcloud.io by acme-client contacting letsencrypt CA
111-
Deployed: in /etc/ssl/simrisk.pulcloud.io.fullchain.pem on the staging.pulcloud.io server
120+
simrisk.pulcloud.io
121+
Purpose: experimental application for CDH
122+
Managed: on staging.pulcloud.io by acme-client contacting letsencrypt CA
123+
Deployed: in /etc/ssl/simrisk.pulcloud.io.fullchain.pem on the staging.pulcloud.io server
112124
Maintained using `/etc/daily.local` as root
113125

114-
tigris.princeton.edu
115-
Purpose: hosted service for University Records management
116-
Managed: in ServiceNow, private key is in princeton_ansible
126+
tigris.princeton.edu
127+
Purpose: hosted service for University Records management
128+
Managed: in ServiceNow, private key is in princeton_ansible
117129
Deployed: by vendor; to update, email a .pfx file of the cert to [email protected]
118130

119-
### Detailed instructions for sites outside the Princeton domain
120-
121-
#### 1. Create the Certificate Signing Request
122-
123-
To generate a CSR manually:
124-
125-
1. For a site with no Subject Alternative Name (SAN)[1]
126-
127-
* Export an environment variable with the host name for later commands
128-
```
129-
export NEW_HOST_NAME=<new host name>
130-
```
131-
* Create a file named `$NEW_HOST_NAME.cnf` with the following command
132-
133-
```ini
134-
echo "[req]
135-
default_bits = 2048
136-
distinguished_name = dn
137-
prompt = no
138-
[dn]
139-
C=\"US\"
140-
ST=\"New Jersey\"
141-
L=\"Princeton\"
142-
O=\"The Trustees of Princeton University\"
143-
OU="OIT"
144-
emailAddress=\"[email protected]\"
145-
CN=\"$NEW_HOST_NAME\"" > $NEW_HOST_NAME.cnf
146-
```
147-
148-
* Generate the certificate which you will provide to
149-
gandi.net with the following command
150-
151-
```bash
152-
openssl req -out ${NEW_HOST_NAME}.csr -newkey rsa:2048 -nodes -keyout ${NEW_HOST_NAME}_priv.key -config ${NEW_HOST_NAME}.cnf
153-
```
154-
155-
The step :point_up_2: above will create `${NEW_HOST_NAME}.csr` and
156-
`${NEW_HOST_NAME}_priv.key` in your current directory.
157-
158-
159-
2. For a site with a Subject Alternative Name (SAN)
160-
161-
* Export an environment variable with the host name for later commands
162-
```
163-
export NEW_HOST_NAME=<new host name>
164-
```
165-
166-
* Create a file named `${NEW_HOSTNAME}_san.cnf` with the following command:
167-
168-
```ini
169-
echo "[ req ]
170-
default_bits = 4096
171-
distinguished_name = dn
172-
req_extensions = req_ext
173-
prompt = no
174-
[ dn ]
175-
C=\"US\"
176-
ST=\"New Jersey\"
177-
L=\"Princeton\"
178-
O=\"The Trustees of Princeton University\"
179-
OU=\"OIT\"
180-
emailAddress=\"[email protected]\"
181-
CN=\"$NEW_HOST_NAME\"
182-
[ req_ext ]
183-
subjectAltName = @alt_names
184-
[alt_names]
185-
DNS.1 = \"${NEW_HOST_NAME}\"
186-
DNS.2 = \"\"" > ${NEW_HOST_NAME}_san.cnf
187-
```
188-
* Edit the file to add your additional Alternative name
189-
190-
* Generate the certificate you will provide to gandi.net
191-
with the following command
192-
193-
```bash
194-
openssl req -out ${NEW_HOST_NAME}.csr -newkey rsa:4096 -nodes -keyout ${NEW_HOST_NAME}_priv.key -config ${NEW_HOST_NAME}_san.cnf
195-
```
196-
197-
The step :point_up_2: above will create `${NEW_HOST_NAME}.csr` and
198-
`${NEW_HOST_NAME}_priv.key` in your current directory.
199-
200-
#### 2. Submit the Certificate request to gandi.net
201-
202-
Submit the CSR to gandi.net. Use the following guidance:
203-
204-
* (SKIP if not SAN) Before submitting it you can check to see if your CSR contains the SAN you
205-
specified in the `${NEW_HOST_NAME}_san.cnf` file by doing.
206-
207-
```bash
208-
openssl req -noout -text -in ${NEW_HOST_NAME}.csr | grep DNS
209-
```
210-
211-
* Provide a `cat`'ed copy of the Certificate Signing Request
212-
with the following command
213-
214-
```
215-
cat ${NEW_HOST_NAME}.csr
216-
```
217-
218-
#### 4. Verify the files you get back
219-
220-
* Gandi.net provides the certificates in the form of an email. You will want the Certificate and Root/Intermediate files:
221-
222-
* `vi ${NEW_HOST_NAME}_cert.cer` and copy and paste including `-----BEGIN CERTIFICATE-----` to `-----END CERTIFICATE-----`
223-
* `vi ${NEW_HOST_NAME}_interm.cer` and copy and paste the rest of the certificates marked as `X.509 Root/Intermediate(s)`. This should have Multiple begin and end certificates, which should be included.
224-
225-
1. Create the chained file from the data returned by gandi.net:
226-
227-
* Concatenate the certificate and the intermediate certificates to create a chained `.pem` file that includes the contents of both files:
228-
229-
```bash
230-
cat ${NEW_HOST_NAME}_cert.cer ${NEW_HOST_NAME}_interm.cer > ${NEW_HOST_NAME}_chained.pem
231-
```
232-
233-
2. Verify the certificates
234-
235-
* Make sure the certificates match (the private key must be unencrypted):
236-
237-
```bash
238-
echo "--Certificate:" && openssl x509 -noout -modulus -in ${NEW_HOST_NAME}_chained.pem && echo "--Key:" && openssl rsa -noout -modulus -in ${NEW_HOST_NAME}_priv.key
239-
```
240-
241-
* Make sure the CN name matches ${NEW_HOST_NAME}:
242-
243-
```bash
244-
openssl x509 -in ${NEW_HOST_NAME}_chained.pem -text
245-
```
246-
247-
3. Save the unencrypted private key for names that are not under ansible control
248-
249-
* Add the unencrypted private key to Shared-SSLCerts directory of LastPass Enterprise
250-
251-
4. Encrypt the private key, and add the encrypted private key and the chained file to princeton-ansible:
252-
253-
* Encrypt the private key with `ansible-vault` and add it to `nginxplus/files/ssl/${NEW_HOST_NAME}_priv.key`
254-
255-
```
256-
cp ${NEW_HOST_NAME}_priv.key roles/nginxplus/files/ssl/
257-
cd roles/nginxplus/files/ssl/
258-
ansible-vault encrypt ${NEW_HOST_NAME}_priv.key
259-
```
260-
* add the chained file to `nginxplus/files/ssl/`
261-
262-
```
263-
mv ${NEW_HOST_NAME}_chained.pem roles/nginxplus/files/ssl/
264-
```
265-
266131
#### Tigris
267132

268-
In July of every year [tigris.princeton.edu](tigris.princeton.edu) will get an automatic renewal. The following steps will be needed to ensure the certificate remains renewed.
133+
In July of every year [tigris.princeton.edu](tigris.princeton.edu) will get an automatic renewal. The following steps will be needed to ensure the certificate remains renewed.
269134
* Open a ticket with tigris (aka Gimmal) support at [email protected] and ask who should receive the new chained file.
270135
* You will need the [vaulted private key](https://github.com/pulibrary/princeton_ansible/blob/main/keys/tigris_princeton_edu_priv.key) and the certificate and intermediate certificate to generate a pfx file that you will ship to the vendor
271136

0 commit comments

Comments
 (0)