Debugged cloud-init script; added script to get user cert.

This commit is contained in:
Pino de Candia 2017-11-21 01:31:36 -06:00
parent 6075058e1d
commit d6f4f557ac
6 changed files with 192 additions and 55 deletions

View File

@ -1,11 +1,87 @@
#cloud-config
mounts:
- [ /dev/disk/by-label/config-2, /mnt/config ]
packages:
- python
- python-requests
write_files:
- path: /etc/ssh/auth_principals/ubuntu
content: webRoot
- path: /etc/ssh/ca_users.pub
content: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDM+YVCEZ4xCqBIGOQOEsGzBzOFS3JNDtPxLAviBMtS4zCwuGmOMvAvatKtPY5E9JMnkhI72faJnwYc4w/pnXf4Sh6AnLfwcOoQ6U16iucfY8tPOeFQhKJokSRdwnfm08QMOHN0xzCA/tL6HHZgPXGHUgTL18kkjv5Zk5Nv1H/ciuOSz24edo94Fu9eIQkK1pUhdejC6hDKdbki/c/3coZU4ZNDdtIpRlGnrUNTaAIq+E0TYEZkgClglTlBQOTvUoRkxEng/U23dfBCCz5DfewfA+6higUil5lIvidbaFjUiTMox38w9fM0wzUUs3o5pC9X/H3BE4mBrfpS9VmYHgll root@Bamboo
- path: /root/setup-ssh.py
permissions: '0700'
owner: root:root
content: |
import json
import requests
import os
import subprocess
import uuid
def getVendordataFromConfigDrive():
path = '/mnt/config/openstack/latest/vendor_data2.json'
with open(path, 'r') as f:
json_string = f.read()
return json.loads(json_string)
def getInstanceAndProjectIdFromConfigDrive():
path = '/mnt/config/openstack/latest/meta_data.json'
with open(path, 'r') as f:
json_string = f.read()
metadata = json.loads(json_string)
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))
vendordata = getVendordataFromConfigDrive()
instance_id, project_id = getInstanceAndProjectIdFromConfigDrive()
assert 'tatu' in vendordata
tatu = vendordata['tatu']
assert 'token' in tatu
assert 'auth_pub_key_user' in tatu
assert 'principals' in tatu
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'
hostcert_request = {
'token_id': tatu['token'],
'host_id': instance_id,
'key.pub': host_key_pub
}
print 'Request the host certificate.'
response = requests.post(
# Hard-coded SSHaaS API address will only work for devstack and requires
# routing and SNAT or DNAT.
# This eventually needs to be either:
# 1) 169.254.169.254 if there's a SSHaaS-proxy; OR
# 2) the real address of the API, possibly supplied in the vendordata and
# still requiring routing and SNAT or DNAT.
server + '/hostcerts',
data=json.dumps(hostcert_request)
)
assert response.status_code == 201
assert 'location' in response.headers
location = response.headers['location']
response = requests.get(server + location)
hostcert = json.loads(response.content)
assert 'host_id' in hostcert
assert hostcert['host_id'] == instance_id
assert 'fingerprint' in hostcert
assert 'auth_id' in hostcert
auth_id = str(uuid.UUID(hostcert['auth_id'], version=4))
assert auth_id == project_id
assert 'key-cert.pub' in hostcert
print 'Begin writing files.'
# Write the host's certificate
with open('/etc/ssh/ssh_host_rsa_key-cert.pub', 'w') as f:
f.write(hostcert['key-cert.pub'])
# Write the authorized principals file
os.mkdir('/etc/ssh/auth_principals')
with open('/etc/ssh/auth_principals/ubuntu', 'w') as f:
for p in principals:
f.write(p + os.linesep)
# Write the User CA public key file
with open('/etc/ssh/ca_user.pub', 'w') as f:
f.write(tatu['auth_pub_key_user'])
print 'All tasks completed.'
runcmd:
- python /root/setup-ssh.py > /var/log/setup-ssh.log 2>&1
- sed -i -e '$aTrustedUserCAKeys /etc/ssh/ca_user.pub' /etc/ssh/sshd_config
- sed -i -e '$aAuthorizedPrincipalsFile /etc/ssh/auth_principals/%u' /etc/ssh/sshd_config
- sed -i -e '$aHostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub' /etc/ssh/sshd_config
- systemctl restart ssh

View File

@ -2,20 +2,15 @@ import json
import requests
import os
import subprocess
import uuid
def getVendordataFromMetadataAPI():
response = requests.get(
'http://169.254.169.254/openstack/2016-10-06/vendor_data2.json',
'http://169.254.169.254/openstack/latest/vendor_data2.json',
)
assert response.status_code == 200
return json.loads(response.content)
def getVendordataFromConfigDrive():
path = '/mnt/openstack/2016-10-06/vendor_data2.json'
with open(path, 'r') as f:
json_string = f.read()
return json.loads(json_string)
def getInstanceAndProjectIdFromMetadataAPI():
response = requests.get(
'http://169.254.169.254/openstack/latest/meta_data.json',
@ -26,35 +21,44 @@ def getInstanceAndProjectIdFromMetadataAPI():
assert 'project_id' in metadata
return metadata['uuid'], metadata['project_id']
def getVendordataFromConfigDrive():
path = '/mnt/config/openstack/latest/vendor_data2.json'
with open(path, 'r') as f:
json_string = f.read()
return json.loads(json_string)
def getInstanceAndProjectIdFromConfigDrive():
path = '/mnt/openstack/latest/meta_data.json'
path = '/mnt/config/openstack/latest/meta_data.json'
with open(path, 'r') as f:
json_string = f.read()
metadata = json.loads(json_string)
assert 'uuid' in metadata
assert 'project_id' in metadata
return metadata['uuid'], metadata['project_id']
return str(uuid.UUID(metadata['uuid'], version=4)), str(uuid.UUID(metadata['project_id'], version=4))
#vendordata = getVendordataFromConfigDrive()
vendordata = getVendordataFromMetadataAPI()
#instance_id = getInstanceIdFromConfigDrive()
instance_id, project_id = getInstanceIdFromMetadataAPI()
vendordata = getVendordataFromConfigDrive()
#vendordata = getVendordataFromMetadataAPI()
instance_id, project_id = getInstanceAndProjectIdFromConfigDrive()
#instance_id, project_id = getInstanceIdFromMetadataAPI()
assert 'sshaas' in vendordata
sshaas = vendordata['sshaas']
assert 'token' in sshaas
assert 'auth_pub_key_user' in sshaas
assert 'principals' in sshaas
principals = sshaas['principals'].split(',')
assert 'tatu' in vendordata
tatu = vendordata['tatu']
assert 'token' in tatu
assert 'auth_pub_key_user' in tatu
assert 'principals' in tatu
principals = tatu['principals'].split(',')
with open('~/.ssh/id_rsa.pub', 'r') as f:
with open('/etc/ssh/ssh_host_rsa_key.pub', 'r') as f:
host_key_pub = f.read()
server = 'http://172.24.4.1:18321'
hostcert_request = {
'token_id': sshaas['token'],
'token_id': tatu['token'],
'host_id': instance_id,
'key.pub': host_key_pub
}
response = requests.post(
# Hard-coded SSHaaS API address will only work for devstack and requires
# routing and SNAT or DNAT.
@ -62,27 +66,27 @@ response = requests.post(
# 1) 169.254.169.254 if there's a SSHaaS-proxy; OR
# 2) the real address of the API, possibly supplied in the vendordata and
# still requiring routing and SNAT or DNAT.
'http://localhost:8000/hostcerts',
server + '/hostcerts',
data=json.dumps(hostcert_request)
)
assert response.status_code == 201
assert 'location' in response.headers
location = response.headers['location']
print location
response = requests.get(
'http://169.254.169.254' + location
)
response = requests.get(server + location)
hostcert = json.loads(response.content)
assert 'host_id' in metadata
assert metadata['host_id'] == instance_id
assert 'fingerprint' in metadata
assert 'auth_id' in metadata
assert metadata['auth_id'] == project_id
assert 'key-cert.pub' in metadata
assert 'host_id' in hostcert
assert hostcert['host_id'] == instance_id
assert 'fingerprint' in hostcert
assert 'auth_id' in hostcert
auth_id = str(uuid.UUID(hostcert['auth_id'], version=4))
assert auth_id == project_id
assert 'key-cert.pub' in hostcert
# Write the host's certificate
with open('/etc/ssh/ssh_host_rsa_key-cert.pub', 'w') as f:
f.write(metadata['key-cert.pub'])
f.write(hostcert['key-cert.pub'])
# Write the authorized principals file
os.mkdir('/etc/ssh/auth_principals')
@ -90,11 +94,11 @@ with open('/etc/ssh/auth_principals/ubuntu', 'w') as f:
for p in principals:
f.write(p + os.linesep)
# Write the UserCA public key file
with open('/etc/ssh/user_ca.pub', 'w') as f:
f.write(sshaas['auth_pub_key_user'])
# Write the User CA public key file
with open('/etc/ssh/ca_user.pub', 'w') as f:
f.write(tatu['auth_pub_key_user'])
subprocess.check_output("sed -i -e '$aTrustedUserCAKeys /etc/ssh/user_ca.pub' /etc/ssh/sshd_config")
subprocess.check_output("sed -i -e '$aTrustedUserCAKeys /etc/ssh/ca_user.pub' /etc/ssh/sshd_config")
subprocess.check_output("sed -i -e '$aAuthorizedPrincipalsFile /etc/ssh/auth_principals/%u' /etc/ssh/sshd_config")
subprocess.check_output("set -i -e '$aHostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub' /etc/ssh/sshd_config")
subprocess.check_output("systemctl restart ssh")
subprocess.check_output("sed -i -e '$aHostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub' /etc/ssh/sshd_config")
subprocess.check_output("systemctl restart ssh")

59
scripts/get_user_cert.py Normal file
View File

@ -0,0 +1,59 @@
import json
import requests
import os
import subprocess
import uuid
from Crypto.PublicKey import RSA
keyfile = '/opt/stack/.ssh/mykey'
user_id = str(uuid.uuid4())
auth_id = str(uuid.UUID('0852c6cd6209425c88de582acbcd1170', version=4))
key = RSA.generate(2048)
keytxt = key.exportKey('PEM')
pubkeytxt = key.publickey().exportKey('OpenSSH')
server = 'http://127.0.0.1:18321'
with open('/etc/ssh/ssh_host_rsa_key.pub', 'r') as f:
host_key_pub = f.read()
user = {
'user_id': user_id,
'auth_id': auth_id,
'key.pub': pubkeytxt
}
response = requests.post(
server + '/usercerts',
data=json.dumps(user)
)
assert response.status_code == 201
assert 'location' in response.headers
location = response.headers['location']
print location
response = requests.get(server + location)
usercert = json.loads(response.content)
assert 'user_id' in usercert
assert usercert['user_id'] == user_id
assert 'fingerprint' in usercert
assert 'auth_id' in usercert
au = str(uuid.UUID(usercert['auth_id'], version=4))
assert au == auth_id
assert 'key-cert.pub' in usercert
# Write the user's ID
with open(keyfile + '_user_id', 'w') as f:
f.write(user_id)
# Write the user private key
with open(keyfile, 'w') as f:
f.write(keytxt)
# Write the user public key
with open(keyfile + '.pub', 'w') as f:
f.write(pubkeytxt)
# Write the user certificate
with open(keyfile + '-cert.pub', 'w') as f:
f.write(usercert['key-cert.pub'])

View File

@ -6,14 +6,11 @@ import falcon
import sshpubkeys
import uuid
import os
from tatu.utils import generateCert
from tatu.utils import generateCert,random_uuid
from Crypto.PublicKey import RSA
Base = declarative_base()
def generate_uuid():
return str(uuid.uuid4())
class Authority(Base):
__tablename__ = 'authorities'
@ -55,7 +52,7 @@ def createUserCert(session, user_id, auth_id, pub):
certRecord = session.query(UserCert).get([user_id, fingerprint])
if certRecord is not None:
raise falcon.HTTPConflict('This public key is already signed.')
cert = generateCert(auth.user_key, pub)
cert = generateCert(auth.user_key, pub, principals='admin,root')
if cert is None:
raise falcon.HTTPInternalServerError("Failed to generate the certificate")
user = UserCert(
@ -72,7 +69,7 @@ class Token(Base):
__tablename__ = 'tokens'
token_id = sa.Column(sa.String(36), primary_key=True,
default=generate_uuid)
default=random_uuid)
auth_id = sa.Column(sa.String(36), sa.ForeignKey('authorities.auth_id'))
host_id = sa.Column(sa.String(36), index=True, unique=True)
hostname = sa.Column(sa.String(36))
@ -140,7 +137,7 @@ def createHostCert(session, token_id, host_id, pub):
certRecord = session.query(HostCert).get([host_id, fingerprint])
if certRecord is not None:
raise falcon.HTTPConflict('This public key is already signed.')
cert = generateCert(auth.host_key, pub, token.hostname)
cert = generateCert(auth.host_key, pub, hostname=token.hostname)
if cert == '':
raise falcon.HTTPInternalServerError("Failed to generate the certificate")
host = HostCert(host_id=host_id,

View File

@ -7,6 +7,7 @@ import uuid
from tatu.api.app import create_app
from tatu.db.persistence import SQLAlchemySessionManager
from tatu.db.models import Authority
from tatu.utils import random_uuid
from Crypto.PublicKey import RSA
import sshpubkeys
@ -19,9 +20,6 @@ def client(db):
api = create_app(db)
return testing.TestClient(api)
def random_uuid():
return str(uuid.uuid4())
token_id = ''
host_id = random_uuid()

View File

@ -2,7 +2,10 @@ import os
import subprocess
import uuid
def generateCert(auth_key, entity_key, hostname=None):
def random_uuid():
return str(uuid.uuid4())
def generateCert(auth_key, entity_key, hostname=None, principals='root'):
# Temporarily write the authority private key and entity public key to files
prefix = uuid.uuid4().hex
# Todo: make the temporary directory configurable or secure it.
@ -20,7 +23,7 @@ def generateCert(auth_key, entity_key, hostname=None):
args = ['ssh-keygen', '-P "pinot"', '-s', ca_file, '-I testID', '-V',
'-1d:+365d', '-n']
if hostname is None:
args.extend(['"myRoot,yourRoot"', pub_file])
args.extend(['"' + principals + '"', pub_file])
else:
args.extend([hostname, '-h', pub_file])
print subprocess.check_output(args, stderr=subprocess.STDOUT)