79 character length

This commit is contained in:
Pino de Candia 2017-12-08 15:11:14 -06:00
parent 7812e1e8b6
commit 3cee92f37f
8 changed files with 116 additions and 84 deletions

View File

@ -16,42 +16,47 @@ import os
import subprocess
import uuid
def getVendordataFromMetadataAPI():
response = requests.get(
'http://169.254.169.254/openstack/latest/vendor_data2.json',
)
assert response.status_code == 200
return json.loads(response.content)
response = requests.get(
'http://169.254.169.254/openstack/latest/vendor_data2.json',
)
assert response.status_code == 200
return json.loads(response.content)
def getInstanceAndProjectIdFromMetadataAPI():
response = requests.get(
'http://169.254.169.254/openstack/latest/meta_data.json',
)
assert response.status_code == 200
metadata = json.loads(response.content)
assert 'uuid' in metadata
assert 'project_id' in metadata
return metadata['uuid'], metadata['project_id']
response = requests.get(
'http://169.254.169.254/openstack/latest/meta_data.json',
)
assert response.status_code == 200
metadata = json.loads(response.content)
assert 'uuid' in metadata
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)
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))
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()
#vendordata = getVendordataFromMetadataAPI()
# vendordata = getVendordataFromMetadataAPI()
instance_id, project_id = getInstanceAndProjectIdFromConfigDrive()
#instance_id, project_id = getInstanceIdFromMetadataAPI()
# instance_id, project_id = getInstanceIdFromMetadataAPI()
assert 'tatu' in vendordata
tatu = vendordata['tatu']
@ -61,25 +66,25 @@ 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()
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
'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.
# 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)
# 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
@ -98,19 +103,19 @@ 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(hostcert['key-cert.pub'])
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)
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'])
f.write(tatu['auth_pub_key_user'])
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("sed -i -e '$aHostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub' /etc/ssh/sshd_config")
subprocess.check_output("systemctl restart ssh")
subprocess.check_output("systemctl restart ssh")

View File

@ -11,9 +11,10 @@
# under the License.
import falcon
import models
import os.path
from oslo_config import cfg
import models
from tatu.castellano import validate_config as validate_castellan_config
from tatu.db.persistence import SQLAlchemySessionManager

View File

@ -14,9 +14,10 @@ import falcon
import json
import logging
import uuid
from tatu.db import models as db
from Crypto.PublicKey import RSA
from tatu.db import models as db
def validate_uuid(map, key):
try:
@ -29,7 +30,8 @@ def validate_uuid(map, key):
def validate_uuids(req, params):
id_keys = ['token_id', 'auth_id', 'host_id', 'user_id', 'project-id', 'instance-id']
id_keys = ['token_id', 'auth_id', 'host_id', 'user_id', 'project-id',
'instance-id']
if req.method in ('POST', 'PUT'):
for key in id_keys:
if key in req.body:
@ -53,7 +55,10 @@ class Logger(object):
self.logger = logging.getLogger(__name__)
def process_resource(self, req, resp, resource, params):
self.logger.debug('Received request {0} {1} with headers {2}'.format(req.method, req.relative_uri, req.headers))
self.logger.debug(
'Received request {0} {1} with headers {2}'.format(req.method,
req.relative_uri,
req.headers))
def process_response(self, req, resp, resource, params):
self.logger.debug(

View File

@ -10,17 +10,18 @@
# License for the specific language governing permissions and limitations
# under the License.
from datetime import datetime
import falcon
import os
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import IntegrityError
import sshpubkeys
from tatu.castellano import get_secret, store_secret
from tatu.utils import generateCert, random_uuid
import uuid
from Crypto.PublicKey import RSA
from datetime import datetime
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from tatu.castellano import get_secret, store_secret
from tatu.utils import generateCert, random_uuid
Base = declarative_base()
@ -78,14 +79,17 @@ def createUserCert(session, user_id, auth_id, pub):
# Retrieve the authority's private key and generate the certificate
auth = getAuthority(session, auth_id)
if auth is None:
raise falcon.HTTPNotFound(description='No Authority found with that ID')
raise falcon.HTTPNotFound(
description='No Authority found with that ID')
fingerprint = sshpubkeys.SSHKey(pub).hash_md5()
certRecord = session.query(UserCert).get([user_id, fingerprint])
if certRecord is not None:
return certRecord
cert = generateCert(get_secret(auth.user_key), pub, principals='admin,root')
cert = generateCert(get_secret(auth.user_key), pub,
principals='admin,root')
if cert is None:
raise falcon.HTTPInternalServerError("Failed to generate the certificate")
raise falcon.HTTPInternalServerError(
"Failed to generate the certificate")
user = UserCert(
user_id=user_id,
fingerprint=fingerprint,
@ -114,7 +118,8 @@ def createToken(session, host_id, auth_id, hostname):
# Validate the certificate authority
auth = getAuthority(session, auth_id)
if auth is None:
raise falcon.HTTPNotFound(description='No Authority found with that ID')
raise falcon.HTTPNotFound(
description='No Authority found with that ID')
# Check whether a token was already created for this host_id
try:
token = session.query(Token).filter(Token.host_id == host_id).one()
@ -152,12 +157,14 @@ def createHostCert(session, token_id, host_id, pub):
if token is None:
raise falcon.HTTPNotFound(description='No Token found with that ID')
if token.host_id != host_id:
raise falcon.HTTPConflict(description='The token is not valid for this instance ID')
raise falcon.HTTPConflict(
description='The token is not valid for this instance ID')
fingerprint = sshpubkeys.SSHKey(pub).hash_md5()
if token.used:
if token.fingerprint_used != fingerprint:
raise falcon.HTTPConflict(description='The token was previously used with a different public key')
raise falcon.HTTPConflict(
description='The token was previously used with a different public key')
# The token was already used for same host and pub key. Return record.
host = session.query(HostCert).get([host_id, fingerprint])
if host is None:
@ -165,17 +172,21 @@ def createHostCert(session, token_id, host_id, pub):
description='The token was used, but no corresponding Host record was found.')
if host.token_id == token_id:
return host
raise falcon.HTTPConflict(description='The presented token was previously used')
raise falcon.HTTPConflict(
description='The presented token was previously used')
auth = getAuthority(session, token.auth_id)
if auth is None:
raise falcon.HTTPNotFound(description='No Authority found with that ID')
raise falcon.HTTPNotFound(
description='No Authority found with that ID')
certRecord = session.query(HostCert).get([host_id, fingerprint])
if certRecord is not None:
raise falcon.HTTPConflict('This public key is already signed.')
cert = generateCert(get_secret(auth.host_key), pub, hostname=token.hostname)
cert = generateCert(get_secret(auth.host_key), pub,
hostname=token.hostname)
if cert == '':
raise falcon.HTTPInternalServerError("Failed to generate the certificate")
raise falcon.HTTPInternalServerError(
"Failed to generate the certificate")
host = HostCert(host_id=host_id,
fingerprint=fingerprint,
auth_id=token.auth_id,

View File

@ -11,9 +11,9 @@
# under the License.
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from tatu.db.models import Base

View File

@ -11,12 +11,13 @@
# under the License.
import json
import requests
import os
from tatu.utils import random_uuid
from Crypto.PublicKey import RSA
import requests
import sshpubkeys
import uuid
from Crypto.PublicKey import RSA
from tatu.utils import random_uuid
server = 'http://172.24.4.1:18322'
@ -68,7 +69,8 @@ def test_host_certificate_generation():
for j in range(3):
response = requests.post(
server + '/novavendordata',
data=json.dumps(vendordata_request(instance_id, project_id, hostname))
data=json.dumps(
vendordata_request(instance_id, project_id, hostname))
)
assert response.status_code == 201
assert 'location' in response.headers

View File

@ -10,17 +10,18 @@
# License for the specific language governing permissions and limitations
# under the License.
import oslo_messaging
import sys
import time
import uuid
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
from oslo_serialization import jsonutils
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
import sys
from tatu.db.models import Base, createAuthority
from tatu.db.persistence import get_url
import time
import uuid
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
@ -52,7 +53,9 @@ class NotificationEndpoint(object):
auth_id = str(uuid.UUID(proj_id, version=4))
createAuthority(se, auth_id)
except Exception as e:
LOG.error("Failed to create Tatu CA for new project with ID {} due to exception {}".format(proj_id, e))
LOG.error(
"Failed to create Tatu CA for new project with ID {} due to exception {}".format(
proj_id, e))
se.rollback()
self.Session.remove()
else:

View File

@ -9,18 +9,19 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import falcon
from falcon import testing
import json
import pytest
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
import time
import uuid
from Crypto.PublicKey import RSA
from falcon import testing
from tatu.api.app import create_app
from tatu.db.models import Authority
from tatu.db.persistence import SQLAlchemySessionManager
from tatu.utils import random_uuid
@pytest.fixture
@ -161,7 +162,8 @@ def test_post_user(client):
@pytest.mark.dependency(depends=['test_post_user'])
def test_get_user(client):
response = client.simulate_get('/usercerts/' + user_id + '/' + user_fingerprint)
response = client.simulate_get(
'/usercerts/' + user_id + '/' + user_fingerprint)
assert response.status == falcon.HTTP_OK
body = json.loads(response.content)
assert 'user_id' in body
@ -172,7 +174,8 @@ def test_get_user(client):
def test_get_user_doesnt_exist(client):
response = client.simulate_get('/usercerts/' + random_uuid() + '/' + user_fingerprint)
response = client.simulate_get(
'/usercerts/' + random_uuid() + '/' + user_fingerprint)
assert response.status == falcon.HTTP_NOT_FOUND
@ -384,7 +387,8 @@ def test_post_token_same_host_id(client):
@pytest.mark.dependency(depends=['test_post_token_and_host'])
def test_get_host(client):
response = client.simulate_get('/hostcerts/' + host_id + '/' + host_fingerprint)
response = client.simulate_get(
'/hostcerts/' + host_id + '/' + host_fingerprint)
assert response.status == falcon.HTTP_OK
body = json.loads(response.content)
assert 'host_id' in body
@ -397,7 +401,8 @@ def test_get_host(client):
def test_get_host_doesnt_exist(client):
response = client.simulate_get('/hostcerts/' + random_uuid() + '/' + host_fingerprint)
response = client.simulate_get(
'/hostcerts/' + random_uuid() + '/' + host_fingerprint)
assert response.status == falcon.HTTP_NOT_FOUND