blob: a1a7fddc181b3f2c5d37725077b0be6826c8e912 [file] [log] [blame]
Dean Troyerc83a7e12012-11-29 11:47:58 -06001# lib/tls
2# Functions to control the configuration and operation of the TLS proxy service
3
Dean Troyerc83a7e12012-11-29 11:47:58 -06004# !! source _before_ any services that use ``SERVICE_HOST``
Adam Spiers6a5aa7c2013-10-24 11:27:02 +01005#
6# Dependencies:
7#
8# - ``functions`` file
9# - ``DEST``, ``DATA_DIR`` must be defined
10# - ``HOST_IP``, ``SERVICE_HOST``
11# - ``KEYSTONE_TOKEN_FORMAT`` must be defined
Dean Troyerc83a7e12012-11-29 11:47:58 -060012
13# Entry points:
Adam Spiers6a5aa7c2013-10-24 11:27:02 +010014#
15# - configure_CA
16# - init_CA
Dean Troyerc83a7e12012-11-29 11:47:58 -060017
Adam Spiers6a5aa7c2013-10-24 11:27:02 +010018# - configure_proxy
19# - start_tls_proxy
Dean Troyerc83a7e12012-11-29 11:47:58 -060020
Adam Spiers6a5aa7c2013-10-24 11:27:02 +010021# - make_root_ca
22# - make_int_ca
23# - new_cert $INT_CA_DIR int-server "abc"
24# - start_tls_proxy HOST_IP 5000 localhost 5000
Dean Troyerc83a7e12012-11-29 11:47:58 -060025
26
Dean Troyercc6b4432013-04-08 15:38:03 -050027# Defaults
28# --------
29
Dean Troyerc83a7e12012-11-29 11:47:58 -060030if is_service_enabled tls-proxy; then
31 # TODO(dtroyer): revisit this below after the search for HOST_IP has been done
32 TLS_IP=${TLS_IP:-$SERVICE_IP}
33
34 # Set the default ``SERVICE_PROTOCOL`` for TLS
35 SERVICE_PROTOCOL=https
36fi
37
38# Make up a hostname for cert purposes
39# will be added to /etc/hosts?
40DEVSTACK_HOSTNAME=secure.devstack.org
41DEVSTACK_CERT_NAME=devstack-cert
42DEVSTACK_CERT=$DATA_DIR/$DEVSTACK_CERT_NAME.pem
43
44# CA configuration
45ROOT_CA_DIR=${ROOT_CA_DIR:-$DATA_DIR/CA/root-ca}
46INT_CA_DIR=${INT_CA_DIR:-$DATA_DIR/CA/int-ca}
47
48ORG_NAME="OpenStack"
49ORG_UNIT_NAME="DevStack"
50
51# Stud configuration
52STUD_PROTO="--tls"
53STUD_CIPHERS='TLSv1+HIGH:!DES:!aNULL:!eNULL:@STRENGTH'
54
55
56# CA Functions
57# ============
58
59# There may be more than one, get specific
60OPENSSL=${OPENSSL:-/usr/bin/openssl}
61
62# Do primary CA configuration
63function configure_CA() {
64 # build common config file
65
66 # Verify ``TLS_IP`` is good
67 if [[ -n "$HOST_IP" && "$HOST_IP" != "$TLS_IP" ]]; then
68 # auto-discover has changed the IP
69 TLS_IP=$HOST_IP
70 fi
71}
72
73# Creates a new CA directory structure
74# create_CA_base ca-dir
75function create_CA_base() {
76 local ca_dir=$1
77
78 if [[ -d $ca_dir ]]; then
79 # Bail out it exists
80 return 0
81 fi
82
83 for i in certs crl newcerts private; do
84 mkdir -p $ca_dir/$i
85 done
86 chmod 710 $ca_dir/private
87 echo "01" >$ca_dir/serial
88 cp /dev/null $ca_dir/index.txt
89}
90
91
92# Create a new CA configuration file
93# create_CA_config ca-dir common-name
94function create_CA_config() {
95 local ca_dir=$1
96 local common_name=$2
97
98 echo "
99[ ca ]
100default_ca = CA_default
101
102[ CA_default ]
103dir = $ca_dir
104policy = policy_match
105database = \$dir/index.txt
106serial = \$dir/serial
107certs = \$dir/certs
108crl_dir = \$dir/crl
109new_certs_dir = \$dir/newcerts
110certificate = \$dir/cacert.pem
111private_key = \$dir/private/cacert.key
112RANDFILE = \$dir/private/.rand
113default_md = default
114
115[ req ]
116default_bits = 1024
117default_md = sha1
118
119prompt = no
120distinguished_name = ca_distinguished_name
121
122x509_extensions = ca_extensions
123
124[ ca_distinguished_name ]
125organizationName = $ORG_NAME
126organizationalUnitName = $ORG_UNIT_NAME Certificate Authority
127commonName = $common_name
128
129[ policy_match ]
130countryName = optional
131stateOrProvinceName = optional
132organizationName = match
133organizationalUnitName = optional
134commonName = supplied
135
136[ ca_extensions ]
137basicConstraints = critical,CA:true
138subjectKeyIdentifier = hash
139authorityKeyIdentifier = keyid:always, issuer
140keyUsage = cRLSign, keyCertSign
141
142" >$ca_dir/ca.conf
143}
144
145# Create a new signing configuration file
146# create_signing_config ca-dir
147function create_signing_config() {
148 local ca_dir=$1
149
150 echo "
151[ ca ]
152default_ca = CA_default
153
154[ CA_default ]
155dir = $ca_dir
156policy = policy_match
157database = \$dir/index.txt
158serial = \$dir/serial
159certs = \$dir/certs
160crl_dir = \$dir/crl
161new_certs_dir = \$dir/newcerts
162certificate = \$dir/cacert.pem
163private_key = \$dir/private/cacert.key
164RANDFILE = \$dir/private/.rand
165default_md = default
166
167[ req ]
168default_bits = 1024
169default_md = sha1
170
171prompt = no
172distinguished_name = req_distinguished_name
173
174x509_extensions = req_extensions
175
176[ req_distinguished_name ]
177organizationName = $ORG_NAME
178organizationalUnitName = $ORG_UNIT_NAME Server Farm
179
180[ policy_match ]
181countryName = optional
182stateOrProvinceName = optional
183organizationName = match
184organizationalUnitName = optional
185commonName = supplied
186
187[ req_extensions ]
188basicConstraints = CA:false
189subjectKeyIdentifier = hash
190authorityKeyIdentifier = keyid:always, issuer
191keyUsage = digitalSignature, keyEncipherment, keyAgreement
192extendedKeyUsage = serverAuth, clientAuth
193subjectAltName = \$ENV::SUBJECT_ALT_NAME
194
195" >$ca_dir/signing.conf
196}
197
Dean Troyerca802172013-01-09 19:08:02 -0600198# Create root and intermediate CAs
Dean Troyerc83a7e12012-11-29 11:47:58 -0600199# init_CA
200function init_CA {
201 # Ensure CAs are built
202 make_root_CA $ROOT_CA_DIR
203 make_int_CA $INT_CA_DIR $ROOT_CA_DIR
204
205 # Create the CA bundle
206 cat $ROOT_CA_DIR/cacert.pem $INT_CA_DIR/cacert.pem >>$INT_CA_DIR/ca-chain.pem
Dean Troyerca802172013-01-09 19:08:02 -0600207}
Dean Troyerc83a7e12012-11-29 11:47:58 -0600208
Dean Troyerca802172013-01-09 19:08:02 -0600209# Create an initial server cert
210# init_cert
211function init_cert {
Dean Troyerc83a7e12012-11-29 11:47:58 -0600212 if [[ ! -r $DEVSTACK_CERT ]]; then
213 if [[ -n "$TLS_IP" ]]; then
214 # Lie to let incomplete match routines work
215 TLS_IP="DNS:$TLS_IP"
216 fi
217 make_cert $INT_CA_DIR $DEVSTACK_CERT_NAME $DEVSTACK_HOSTNAME "$TLS_IP"
218
219 # Create a cert bundle
220 cat $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/cacert.pem >$DEVSTACK_CERT
221 fi
222}
223
224
225# make_cert creates and signs a new certificate with the given commonName and CA
226# make_cert ca-dir cert-name "common-name" ["alt-name" ...]
227function make_cert() {
228 local ca_dir=$1
229 local cert_name=$2
230 local common_name=$3
231 local alt_names=$4
232
233 # Generate a signing request
234 $OPENSSL req \
235 -sha1 \
236 -newkey rsa \
237 -nodes \
238 -keyout $ca_dir/private/$cert_name.key \
239 -out $ca_dir/$cert_name.csr \
240 -subj "/O=${ORG_NAME}/OU=${ORG_UNIT_NAME} Servers/CN=${common_name}"
241
242 if [[ -z "$alt_names" ]]; then
243 alt_names="DNS:${common_name}"
244 else
245 alt_names="DNS:${common_name},${alt_names}"
246 fi
247
248 # Sign the request valid for 1 year
249 SUBJECT_ALT_NAME="$alt_names" \
250 $OPENSSL ca -config $ca_dir/signing.conf \
251 -extensions req_extensions \
252 -days 365 \
253 -notext \
254 -in $ca_dir/$cert_name.csr \
255 -out $ca_dir/$cert_name.crt \
256 -subj "/O=${ORG_NAME}/OU=${ORG_UNIT_NAME} Servers/CN=${common_name}" \
257 -batch
258}
259
260
261# Make an intermediate CA to sign everything else
262# make_int_CA ca-dir signing-ca-dir
263function make_int_CA() {
264 local ca_dir=$1
265 local signing_ca_dir=$2
266
267 # Create the root CA
268 create_CA_base $ca_dir
269 create_CA_config $ca_dir 'Intermediate CA'
270 create_signing_config $ca_dir
271
272 # Create a signing certificate request
273 $OPENSSL req -config $ca_dir/ca.conf \
274 -sha1 \
275 -newkey rsa \
276 -nodes \
277 -keyout $ca_dir/private/cacert.key \
278 -out $ca_dir/cacert.csr \
279 -outform PEM
280
281 # Sign the intermediate request valid for 1 year
282 $OPENSSL ca -config $signing_ca_dir/ca.conf \
283 -extensions ca_extensions \
284 -days 365 \
285 -notext \
286 -in $ca_dir/cacert.csr \
287 -out $ca_dir/cacert.pem \
288 -batch
289}
290
291# Make a root CA to sign other CAs
292# make_root_CA ca-dir
293function make_root_CA() {
294 local ca_dir=$1
295
296 # Create the root CA
297 create_CA_base $ca_dir
298 create_CA_config $ca_dir 'Root CA'
299
300 # Create a self-signed certificate valid for 5 years
301 $OPENSSL req -config $ca_dir/ca.conf \
302 -x509 \
303 -nodes \
304 -newkey rsa \
305 -days 21360 \
306 -keyout $ca_dir/private/cacert.key \
307 -out $ca_dir/cacert.pem \
308 -outform PEM
309}
310
311
312# Proxy Functions
313# ===============
314
315# Starts the TLS proxy for the given IP/ports
316# start_tls_proxy front-host front-port back-host back-port
317function start_tls_proxy() {
318 local f_host=$1
319 local f_port=$2
320 local b_host=$3
321 local b_port=$4
322
323 stud $STUD_PROTO -f $f_host,$f_port -b $b_host,$b_port $DEVSTACK_CERT 2>/dev/null
324}
Sean Dague584d90e2013-03-29 14:34:53 -0400325
Dean Troyercc6b4432013-04-08 15:38:03 -0500326
Adam Spiers6a5aa7c2013-10-24 11:27:02 +0100327# Tell emacs to use shell-script-mode
328## Local variables:
329## mode: shell-script
330## End: