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