Skip to content

Commit c83a7e1

Browse files
author
Dean Troyer
committed
Add TLS support for keystone via proxy
* Adds lib/tls to create test CA/certs * Start proxy if 'tls-proxy' is enabled * Configure keystone service catalog for TLS * Tear down proxy in unstack.sh * Set auth protocol and ca-cert chain in openrc * Add DATA_DIR to stackrc This is the first in a series of patches to enable TLS support for the service API endpoints. Change-Id: Ia1c91dc8f1aaf94fbec9dc71da322559a83d14b6
1 parent 00626a3 commit c83a7e1

7 files changed

Lines changed: 376 additions & 10 deletions

File tree

files/apts/tls-proxy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
stud

lib/keystone

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Dependencies:
55
# ``functions`` file
66
# ``BASE_SQL_CONN``
7-
# ``SERVICE_HOST``
7+
# ``SERVICE_HOST``, ``SERVICE_PROTOCOL``
88
# ``SERVICE_TOKEN``
99
# ``S3_SERVICE_PORT`` (template backend only)
1010

@@ -48,10 +48,14 @@ KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-PKI}
4848
# Set Keystone interface configuration
4949
KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST}
5050
KEYSTONE_AUTH_PORT=${KEYSTONE_AUTH_PORT:-35357}
51-
KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-http}
51+
KEYSTONE_AUTH_PORT_INT=${KEYSTONE_AUTH_PORT_INT:-35358}
52+
KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-$SERVICE_PROTOCOL}
53+
54+
# Public facing bits
5255
KEYSTONE_SERVICE_HOST=${KEYSTONE_SERVICE_HOST:-$SERVICE_HOST}
5356
KEYSTONE_SERVICE_PORT=${KEYSTONE_SERVICE_PORT:-5000}
54-
KEYSTONE_SERVICE_PROTOCOL=${KEYSTONE_SERVICE_PROTOCOL:-http}
57+
KEYSTONE_SERVICE_PORT_INT=${KEYSTONE_SERVICE_PORT_INT:-5001}
58+
KEYSTONE_SERVICE_PROTOCOL=${KEYSTONE_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
5559

5660

5761
# Entry Points
@@ -88,6 +92,13 @@ function configure_keystone() {
8892
# Rewrite stock ``keystone.conf``
8993
local dburl
9094
database_connection_url dburl keystone
95+
96+
if is_service_enabled tls-proxy; then
97+
# Set the service ports for a proxy to take the originals
98+
iniset $KEYSTONE_CONF DEFAULT public_port $KEYSTONE_SERVICE_PORT_INT
99+
iniset $KEYSTONE_CONF DEFAULT admin_port $KEYSTONE_AUTH_PORT_INT
100+
fi
101+
91102
iniset $KEYSTONE_CONF DEFAULT admin_token "$SERVICE_TOKEN"
92103
iniset $KEYSTONE_CONF signing token_format "$KEYSTONE_TOKEN_FORMAT"
93104
iniset $KEYSTONE_CONF sql connection $dburl
@@ -213,9 +224,9 @@ create_keystone_accounts() {
213224
keystone endpoint-create \
214225
--region RegionOne \
215226
--service_id $KEYSTONE_SERVICE \
216-
--publicurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:\$(public_port)s/v2.0" \
217-
--adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:\$(admin_port)s/v2.0" \
218-
--internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:\$(public_port)s/v2.0"
227+
--publicurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0" \
228+
--adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0" \
229+
--internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0"
219230
fi
220231

221232
# TODO(dtroyer): This is part of a series of changes...remove these when
@@ -268,13 +279,25 @@ function install_keystone() {
268279

269280
# start_keystone() - Start running processes, including screen
270281
function start_keystone() {
282+
# Get right service port for testing
283+
local service_port=$KEYSTONE_SERVICE_PORT
284+
if is_service_enabled tls-proxy; then
285+
service_port=$KEYSTONE_SERVICE_PORT_INT
286+
fi
287+
271288
# Start Keystone in a screen window
272289
screen_it key "cd $KEYSTONE_DIR && $KEYSTONE_DIR/bin/keystone-all --config-file $KEYSTONE_CONF $KEYSTONE_LOG_CONFIG -d --debug"
273290
echo "Waiting for keystone to start..."
274-
if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= curl -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/ >/dev/null; do sleep 1; done"; then
291+
if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= curl -s http://$SERVICE_HOST:$service_port/v2.0/ >/dev/null; do sleep 1; done"; then
275292
echo "keystone did not start"
276293
exit 1
277294
fi
295+
296+
# Start proxies if enabled
297+
if is_service_enabled tls-proxy; then
298+
start_tls_proxy '*' $KEYSTONE_SERVICE_PORT $KEYSTONE_SERVICE_HOST $KEYSTONE_SERVICE_PORT_INT &
299+
start_tls_proxy '*' $KEYSTONE_AUTH_PORT $KEYSTONE_AUTH_HOST $KEYSTONE_AUTH_PORT_INT &
300+
fi
278301
}
279302

280303
# stop_keystone() - Stop running processes

lib/tls

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# 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+
24+
if 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
30+
fi
31+
32+
# Make up a hostname for cert purposes
33+
# will be added to /etc/hosts?
34+
DEVSTACK_HOSTNAME=secure.devstack.org
35+
DEVSTACK_CERT_NAME=devstack-cert
36+
DEVSTACK_CERT=$DATA_DIR/$DEVSTACK_CERT_NAME.pem
37+
38+
# CA configuration
39+
ROOT_CA_DIR=${ROOT_CA_DIR:-$DATA_DIR/CA/root-ca}
40+
INT_CA_DIR=${INT_CA_DIR:-$DATA_DIR/CA/int-ca}
41+
42+
ORG_NAME="OpenStack"
43+
ORG_UNIT_NAME="DevStack"
44+
45+
# Stud configuration
46+
STUD_PROTO="--tls"
47+
STUD_CIPHERS='TLSv1+HIGH:!DES:!aNULL:!eNULL:@STRENGTH'
48+
49+
50+
# CA Functions
51+
# ============
52+
53+
# There may be more than one, get specific
54+
OPENSSL=${OPENSSL:-/usr/bin/openssl}
55+
56+
# Do primary CA configuration
57+
function 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
69+
function 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
88+
function create_CA_config() {
89+
local ca_dir=$1
90+
local common_name=$2
91+
92+
echo "
93+
[ ca ]
94+
default_ca = CA_default
95+
96+
[ CA_default ]
97+
dir = $ca_dir
98+
policy = policy_match
99+
database = \$dir/index.txt
100+
serial = \$dir/serial
101+
certs = \$dir/certs
102+
crl_dir = \$dir/crl
103+
new_certs_dir = \$dir/newcerts
104+
certificate = \$dir/cacert.pem
105+
private_key = \$dir/private/cacert.key
106+
RANDFILE = \$dir/private/.rand
107+
default_md = default
108+
109+
[ req ]
110+
default_bits = 1024
111+
default_md = sha1
112+
113+
prompt = no
114+
distinguished_name = ca_distinguished_name
115+
116+
x509_extensions = ca_extensions
117+
118+
[ ca_distinguished_name ]
119+
organizationName = $ORG_NAME
120+
organizationalUnitName = $ORG_UNIT_NAME Certificate Authority
121+
commonName = $common_name
122+
123+
[ policy_match ]
124+
countryName = optional
125+
stateOrProvinceName = optional
126+
organizationName = match
127+
organizationalUnitName = optional
128+
commonName = supplied
129+
130+
[ ca_extensions ]
131+
basicConstraints = critical,CA:true
132+
subjectKeyIdentifier = hash
133+
authorityKeyIdentifier = keyid:always, issuer
134+
keyUsage = cRLSign, keyCertSign
135+
136+
" >$ca_dir/ca.conf
137+
}
138+
139+
# Create a new signing configuration file
140+
# create_signing_config ca-dir
141+
function create_signing_config() {
142+
local ca_dir=$1
143+
144+
echo "
145+
[ ca ]
146+
default_ca = CA_default
147+
148+
[ CA_default ]
149+
dir = $ca_dir
150+
policy = policy_match
151+
database = \$dir/index.txt
152+
serial = \$dir/serial
153+
certs = \$dir/certs
154+
crl_dir = \$dir/crl
155+
new_certs_dir = \$dir/newcerts
156+
certificate = \$dir/cacert.pem
157+
private_key = \$dir/private/cacert.key
158+
RANDFILE = \$dir/private/.rand
159+
default_md = default
160+
161+
[ req ]
162+
default_bits = 1024
163+
default_md = sha1
164+
165+
prompt = no
166+
distinguished_name = req_distinguished_name
167+
168+
x509_extensions = req_extensions
169+
170+
[ req_distinguished_name ]
171+
organizationName = $ORG_NAME
172+
organizationalUnitName = $ORG_UNIT_NAME Server Farm
173+
174+
[ policy_match ]
175+
countryName = optional
176+
stateOrProvinceName = optional
177+
organizationName = match
178+
organizationalUnitName = optional
179+
commonName = supplied
180+
181+
[ req_extensions ]
182+
basicConstraints = CA:false
183+
subjectKeyIdentifier = hash
184+
authorityKeyIdentifier = keyid:always, issuer
185+
keyUsage = digitalSignature, keyEncipherment, keyAgreement
186+
extendedKeyUsage = serverAuth, clientAuth
187+
subjectAltName = \$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
194+
function 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" ...]
217+
function 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
253+
function 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
283+
function 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
307+
function 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+
}

0 commit comments

Comments
 (0)