Provide ssh setup script via static vendor data.
This commit is contained in:
parent
6235f5e2b0
commit
857d4dd028
1
files/static-vendor-data.json
Normal file
1
files/static-vendor-data.json
Normal file
@ -0,0 +1 @@
|
||||
{"cloud-init": "#cloud-config\nmounts:\n - [ /dev/disk/by-label/config-2, /mnt/config ]\npackages:\n - python\n - python-requests\nwrite_files:\n - path: /root/setup-ssh.py\n permissions: '0700'\n owner: root:root\n content: |\n print 'Importing packages'\n import json\n import requests\n import os\n import subprocess\n import uuid\n def getVendordataFromConfigDrive():\n path = '/mnt/config/openstack/latest/vendor_data2.json'\n with open(path, 'r') as f:\n json_string = f.read()\n return json.loads(json_string)\n def getInstanceAndProjectIdFromConfigDrive():\n path = '/mnt/config/openstack/latest/meta_data.json'\n with open(path, 'r') as f:\n json_string = f.read()\n metadata = json.loads(json_string)\n assert 'uuid' in metadata\n assert 'project_id' in metadata\n return str(uuid.UUID(metadata['uuid'], version=4)), str(uuid.UUID(metadata['project_id'], version=4))\n print 'Getting vendordata from ConfigDrive'\n vendordata = getVendordataFromConfigDrive()\n print 'Getting instance and project IDs'\n instance_id, project_id = getInstanceAndProjectIdFromConfigDrive()\n assert 'tatu' in vendordata\n tatu = vendordata['tatu']\n assert 'token' in tatu\n assert 'auth_pub_key_user' in tatu\n assert 'principals' in tatu\n principals = tatu['principals'].split(',')\n with open('/etc/ssh/ssh_host_rsa_key.pub', 'r') as f:\n host_key_pub = f.read()\n server = 'http://172.24.4.1:18322'\n hostcert_request = {\n 'token_id': tatu['token'],\n 'host_id': instance_id,\n 'key.pub': host_key_pub\n }\n print 'Request the host certificate.'\n response = requests.post(\n # Hard-coded SSHaaS API address will only work for devstack and requires\n # routing and SNAT or DNAT.\n # This eventually needs to be either:\n # 1) 169.254.169.254 if there's a SSHaaS-proxy; OR\n # 2) the real address of the API, possibly supplied in the vendordata and\n # still requiring routing and SNAT or DNAT.\n server + '/hostcerts',\n data=json.dumps(hostcert_request)\n )\n print 'Got the host certificate: {}'.format(response.content)\n assert response.status_code == 201\n assert 'location' in response.headers\n location = response.headers['location']\n # No need to GET the host cert - it's returned in the POST\n #response = requests.get(server + location)\n hostcert = json.loads(response.content)\n assert 'host_id' in hostcert\n assert hostcert['host_id'] == instance_id\n assert 'fingerprint' in hostcert\n assert 'auth_id' in hostcert\n auth_id = str(uuid.UUID(hostcert['auth_id'], version=4))\n assert auth_id == project_id\n assert 'key-cert.pub' in hostcert\n print 'Begin writing files.'\n # Write the host's certificate\n with open('/etc/ssh/ssh_host_rsa_key-cert.pub', 'w') as f:\n f.write(hostcert['key-cert.pub'])\n # Write the authorized principals file\n os.mkdir('/etc/ssh/auth_principals')\n with open('/etc/ssh/auth_principals/ubuntu', 'w') as f:\n for p in principals:\n f.write(p + os.linesep)\n # Write the User CA public key file\n with open('/etc/ssh/ca_user.pub', 'w') as f:\n f.write(tatu['auth_pub_key_user'])\n print 'All tasks completed.'\nruncmd:\n - python /root/setup-ssh.py > /var/log/setup-ssh.log 2>&1\n - sed -i -e '$aTrustedUserCAKeys /etc/ssh/ca_user.pub' /etc/ssh/sshd_config\n - sed -i -e '$aAuthorizedPrincipalsFile /etc/ssh/auth_principals/%u' /etc/ssh/sshd_config\n - sed -i -e '$aHostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub' /etc/ssh/sshd_config\n - systemctl restart ssh\n"}
|
@ -9,6 +9,7 @@ write_files:
|
||||
permissions: '0700'
|
||||
owner: root:root
|
||||
content: |
|
||||
print 'Importing packages'
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
@ -27,7 +28,9 @@ write_files:
|
||||
assert 'uuid' in metadata
|
||||
assert 'project_id' in metadata
|
||||
return str(uuid.UUID(metadata['uuid'], version=4)), str(uuid.UUID(metadata['project_id'], version=4))
|
||||
print 'Getting vendordata from ConfigDrive'
|
||||
vendordata = getVendordataFromConfigDrive()
|
||||
print 'Getting instance and project IDs'
|
||||
instance_id, project_id = getInstanceAndProjectIdFromConfigDrive()
|
||||
assert 'tatu' in vendordata
|
||||
tatu = vendordata['tatu']
|
||||
@ -37,7 +40,7 @@ write_files:
|
||||
principals = tatu['principals'].split(',')
|
||||
with open('/etc/ssh/ssh_host_rsa_key.pub', 'r') as f:
|
||||
host_key_pub = f.read()
|
||||
server = 'http://172.24.4.1:18321'
|
||||
server = 'http://172.24.4.1:18322'
|
||||
hostcert_request = {
|
||||
'token_id': tatu['token'],
|
||||
'host_id': instance_id,
|
||||
@ -54,10 +57,12 @@ write_files:
|
||||
server + '/hostcerts',
|
||||
data=json.dumps(hostcert_request)
|
||||
)
|
||||
print 'Got the host certificate: {}'.format(response.content)
|
||||
assert response.status_code == 201
|
||||
assert 'location' in response.headers
|
||||
location = response.headers['location']
|
||||
response = requests.get(server + location)
|
||||
# No need to GET the host cert - it's returned in the POST
|
||||
#response = requests.get(server + location)
|
||||
hostcert = json.loads(response.content)
|
||||
assert 'host_id' in hostcert
|
||||
assert hostcert['host_id'] == instance_id
|
||||
|
@ -7,6 +7,4 @@ import yaml
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
yaml_string = f.read()
|
||||
|
||||
# save to file:
|
||||
with open(sys.argv[2], 'w') as f:
|
||||
f.write(json.dumps({"cloud-init":yaml_string}))
|
||||
print json.dumps({"cloud-init":yaml_string})
|
||||
|
@ -7,7 +7,4 @@ import yaml
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
js = json.loads(f.read())
|
||||
|
||||
# save to file:
|
||||
#with open(sys.argv[2], 'w') as f:
|
||||
# f.write(js['cloud-init'])
|
||||
print js['cloud-init']
|
||||
|
@ -115,6 +115,14 @@ class UserCert(object):
|
||||
resp.body = json.dumps(body)
|
||||
resp.status = falcon.HTTP_OK
|
||||
|
||||
def hostToJson(host):
|
||||
return json.dumps({
|
||||
'host_id': host.host_id,
|
||||
'fingerprint': host.fingerprint,
|
||||
'auth_id': host.auth_id,
|
||||
'key-cert.pub': host.cert,
|
||||
})
|
||||
|
||||
class HostCerts(object):
|
||||
|
||||
@falcon.before(validate)
|
||||
@ -130,6 +138,7 @@ class HostCerts(object):
|
||||
)
|
||||
except KeyError as e:
|
||||
raise falcon.HTTPBadRequest(str(e))
|
||||
resp.body = hostToJson(host)
|
||||
resp.status = falcon.HTTP_201
|
||||
resp.location = '/hostcerts/' + host.host_id + '/' + host.fingerprint
|
||||
|
||||
@ -141,13 +150,7 @@ class HostCert(object):
|
||||
if host is None:
|
||||
resp.status = falcon.HTTP_NOT_FOUND
|
||||
return
|
||||
body = {
|
||||
'host_id': host.host_id,
|
||||
'fingerprint': host.fingerprint,
|
||||
'auth_id': host.auth_id,
|
||||
'key-cert.pub': host.cert,
|
||||
}
|
||||
resp.body = json.dumps(body)
|
||||
resp.body = hostToJson(host)
|
||||
resp.status = falcon.HTTP_OK
|
||||
|
||||
class Tokens(object):
|
||||
|
@ -6,7 +6,7 @@ from Crypto.PublicKey import RSA
|
||||
import sshpubkeys
|
||||
import uuid
|
||||
|
||||
server = 'http://127.0.0.1:18321'
|
||||
server = 'http://172.24.4.1:18322'
|
||||
|
||||
def vendordata_request(instance_id, project_id, hostname):
|
||||
return {
|
||||
@ -44,7 +44,7 @@ def test_host_certificate_generation():
|
||||
key = RSA.generate(2048)
|
||||
pub_key = key.publickey().exportKey('OpenSSH')
|
||||
fingerprint = sshpubkeys.SSHKey(pub_key).hash_md5()
|
||||
for i in range(100):
|
||||
for i in range(10):
|
||||
instance_id = random_uuid()
|
||||
hostname = 'host{}'.format(i)
|
||||
# Simulate Nova's separate requests for each version of metadata API
|
||||
|
@ -284,6 +284,18 @@ def test_post_token_and_host(client):
|
||||
assert location[1] == 'hostcerts'
|
||||
assert location[2] == host_id
|
||||
assert location[3] == host_fingerprint
|
||||
# Re-trying the same exact calls returns identical results
|
||||
response = client.simulate_post(
|
||||
'/hostcerts',
|
||||
body=json.dumps(host)
|
||||
)
|
||||
assert response.status == falcon.HTTP_CREATED
|
||||
assert 'location' in response.headers
|
||||
location = response.headers['location'].split('/')
|
||||
assert location[1] == 'hostcerts'
|
||||
assert location[2] == host_id
|
||||
assert location[3] == host_fingerprint
|
||||
|
||||
|
||||
def test_stress_post_token_and_host(client):
|
||||
my_auth_id = random_uuid()
|
||||
|
Loading…
Reference in New Issue
Block a user