blob: 1e2a8993dce2063f3be17033e6cef3f0b37821a5 [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
192# Create root and intermediate CAs and an initial server cert
193# 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
201
202 if [[ ! -r $DEVSTACK_CERT ]]; then
203 if [[ -n "$TLS_IP" ]]; then
204 # Lie to let incomplete match routines work
205 TLS_IP="DNS:$TLS_IP"
206 fi
207 make_cert $INT_CA_DIR $DEVSTACK_CERT_NAME $DEVSTACK_HOSTNAME "$TLS_IP"
208
209 # Create a cert bundle
210 cat $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/cacert.pem >$DEVSTACK_CERT
211 fi
212}
213
214
215# make_cert creates and signs a new certificate with the given commonName and CA
216# make_cert ca-dir cert-name "common-name" ["alt-name" ...]
217function make_cert() {
218 local ca_dir=$1
219 local cert_name=$2
220 local common_name=$3
221 local alt_names=$4
222
223 # Generate a signing request
224 $OPENSSL req \
225 -sha1 \
226 -newkey rsa \
227 -nodes \
228 -keyout $ca_dir/private/$cert_name.key \
229 -out $ca_dir/$cert_name.csr \
230 -subj "/O=${ORG_NAME}/OU=${ORG_UNIT_NAME} Servers/CN=${common_name}"
231
232 if [[ -z "$alt_names" ]]; then
233 alt_names="DNS:${common_name}"
234 else
235 alt_names="DNS:${common_name},${alt_names}"
236 fi
237
238 # Sign the request valid for 1 year
239 SUBJECT_ALT_NAME="$alt_names" \
240 $OPENSSL ca -config $ca_dir/signing.conf \
241 -extensions req_extensions \
242 -days 365 \
243 -notext \
244 -in $ca_dir/$cert_name.csr \
245 -out $ca_dir/$cert_name.crt \
246 -subj "/O=${ORG_NAME}/OU=${ORG_UNIT_NAME} Servers/CN=${common_name}" \
247 -batch
248}
249
250
251# Make an intermediate CA to sign everything else
252# make_int_CA ca-dir signing-ca-dir
253function make_int_CA() {
254 local ca_dir=$1
255 local signing_ca_dir=$2
256
257 # Create the root CA
258 create_CA_base $ca_dir
259 create_CA_config $ca_dir 'Intermediate CA'
260 create_signing_config $ca_dir
261
262 # Create a signing certificate request
263 $OPENSSL req -config $ca_dir/ca.conf \
264 -sha1 \
265 -newkey rsa \
266 -nodes \
267 -keyout $ca_dir/private/cacert.key \
268 -out $ca_dir/cacert.csr \
269 -outform PEM
270
271 # Sign the intermediate request valid for 1 year
272 $OPENSSL ca -config $signing_ca_dir/ca.conf \
273 -extensions ca_extensions \
274 -days 365 \
275 -notext \
276 -in $ca_dir/cacert.csr \
277 -out $ca_dir/cacert.pem \
278 -batch
279}
280
281# Make a root CA to sign other CAs
282# make_root_CA ca-dir
283function make_root_CA() {
284 local ca_dir=$1
285
286 # Create the root CA
287 create_CA_base $ca_dir
288 create_CA_config $ca_dir 'Root CA'
289
290 # Create a self-signed certificate valid for 5 years
291 $OPENSSL req -config $ca_dir/ca.conf \
292 -x509 \
293 -nodes \
294 -newkey rsa \
295 -days 21360 \
296 -keyout $ca_dir/private/cacert.key \
297 -out $ca_dir/cacert.pem \
298 -outform PEM
299}
300
301
302# Proxy Functions
303# ===============
304
305# Starts the TLS proxy for the given IP/ports
306# start_tls_proxy front-host front-port back-host back-port
307function start_tls_proxy() {
308 local f_host=$1
309 local f_port=$2
310 local b_host=$3
311 local b_port=$4
312
313 stud $STUD_PROTO -f $f_host,$f_port -b $b_host,$b_port $DEVSTACK_CERT 2>/dev/null
314}