79 character length
This commit is contained in:
parent
7812e1e8b6
commit
3cee92f37f
@ -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")
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user