-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
92 lines (71 loc) · 3.09 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
from oslo_config import cfg
from waitress import serve as waitress_serve
from flask import Flask, request, jsonify
from keystonemiddleware import auth_token
from oidc import OIDCProvider
CONF = cfg.CONF
common_opts = [
cfg.StrOpt('listen_host', default="0.0.0.0",
help="Host the service listens to"),
cfg.IntOpt('listen_port', default=8001,
help="Port the service listens to"),
]
CONF.register_opts(common_opts)
oidc_provider_opts = [
cfg.StrOpt('issuer_url', default="https://idp.example.com",
help="URL of the OIDC issuer of the generated tokens"),
cfg.StrOpt('audience', default="openstack",
help="OIDC audience of generated tokens"),
cfg.StrOpt('private_key_path', default="private_key.pem",
help="Path to private key"),
cfg.StrOpt('public_key_path', default="public_key.pem",
help="Path to public key"),
cfg.IntOpt('token_lifetime', default=1,
help="Lifetime of generated tokens in hours"),
]
oidc_provider_config = cfg.OptGroup(
name='oidc_provider', title="OIDC Provider Options")
CONF.register_group(oidc_provider_config)
CONF.register_opts(oidc_provider_opts, group=oidc_provider_config)
config_file = 'nova-instance-identity.conf'
CONF(default_config_files=[config_file])
def wrap_keystone_middleware(app):
"""Keystone middleware wrapper for paths which require authentication"""
# Paths which bypass Keystone authentication
paths_to_exclude = ['/.well-known']
class AuthMiddlewareWrapper:
def __init__(self, app):
self.app = app
self.keystone_middleware = auth_token.AuthProtocol(self.app, {})
def __call__(self, environ, start_response):
# If current path starts with a string defined in excluded path list, skip Keystone authentication
if any(environ['PATH_INFO'].startswith(path) for path in paths_to_exclude):
return self.app(environ, start_response)
# Enforce Keystone authentication
return self.keystone_middleware(environ, start_response)
return AuthMiddlewareWrapper(app)
app = Flask(__name__)
app.wsgi_app = wrap_keystone_middleware(app.wsgi_app)
oidc_provider = OIDCProvider(app, CONF.oidc_provider)
@ app.route('/vendordata/instance-identity', methods=['POST'])
def vendordata():
"""Create response to Nova vendordata request with instance identity token"""
data = request.get_json()
payload = {
'instance-id': data['instance-id'],
'project-id': data['project-id'],
'image-id': data['image-id'],
'hostname': data['hostname'],
'metadata': data['metadata'],
}
if 'assume-role' in data['metadata']:
payload['assume-role'] = data['metadata']['assume-role']
token, expires_at = oidc_provider.create_token(
data['instance-id'], payload)
return jsonify({
'token': token,
'expires_at': expires_at,
})
if __name__ == '__main__':
print(f"Starting server on {CONF.listen_host}:{CONF.listen_port}")
waitress_serve(app, host=CONF.listen_host, port=CONF.listen_port)