Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions bless/aws_lambda/bless_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import kmsauth
from bless.config.bless_config import BlessConfig, BLESS_OPTIONS_SECTION, \
CERTIFICATE_VALIDITY_WINDOW_SEC_OPTION, ENTROPY_MINIMUM_BITS_OPTION, RANDOM_SEED_BYTES_OPTION, \
BLESS_CA_SECTION, CA_PRIVATE_KEY_FILE_OPTION, LOGGING_LEVEL_OPTION, KMSAUTH_SERVICE_ID_OPTION
BLESS_CA_SECTION, CA_PRIVATE_KEY_FILE_OPTION, LOGGING_LEVEL_OPTION, KMSAUTH_SECTION, \
KMSAUTH_USEKMSAUTH_OPTION, KMSAUTH_SERVICE_ID_OPTION

from bless.request.bless_request import BlessSchema
from bless.ssh.certificate_authorities.ssh_certificate_authority_factory import \
get_ssh_certificate_authority
Expand Down Expand Up @@ -56,7 +58,6 @@ def lambda_handler(event, context=None, ca_private_key_password=None,
random_seed_bytes = config.getint(BLESS_OPTIONS_SECTION, RANDOM_SEED_BYTES_OPTION)
ca_private_key_file = config.get(BLESS_CA_SECTION, CA_PRIVATE_KEY_FILE_OPTION)
password_ciphertext_b64 = config.getpassword()
kmsauth_key_id = config.getkmsauthkeyid()

# read the private key .pem
with open(os.path.join(os.path.dirname(__file__), ca_private_key_file), 'r') as f:
Expand Down Expand Up @@ -95,17 +96,19 @@ def lambda_handler(event, context=None, ca_private_key_password=None,
valid_after = current_time - certificate_validity_window_seconds

# Authenticate the user with KMS, if key is setup
if (kmsauth_key_id):
if (request.kmsauth_token):
kmsauth_to = config.get(BLESS_CA_SECTION, KMSAUTH_SERVICE_ID_OPTION)
if config.get(KMSAUTH_SECTION, KMSAUTH_USEKMSAUTH_OPTION):
if request.kmsauth_token:
validator = kmsauth.KMSTokenValidator(
kmsauth_key_id,
kmsauth_key_id,
kmsauth_to,
None,
config.getkmsauthkeyids(),
config.get(KMSAUTH_SECTION, KMSAUTH_SERVICE_ID_OPTION),
region
)
# decrypt_token will raise a TokenValidationError if token doesn't match
validator.decrypt_token("2/user/{}".format(request.remote_username), request.kmsauth_token)
validator.decrypt_token(
"2/user/{}".format(request.remote_username),
request.kmsauth_token
)
else:
raise ValueError('Invalid request, missing kmsauth token')

Expand Down
31 changes: 19 additions & 12 deletions bless/config/bless_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@
CA_PRIVATE_KEY_FILE_OPTION = 'ca_private_key_file'
KMS_KEY_ID_OPTION = 'kms_key_id'

KMSAUTH_KEY_ID_SUFFIX = '_kmsauth_key_id'
KMSAUTH_KEY_ID_DEFAULT = None
REGION_PASSWORD_OPTION_SUFFIX = '_password'

KMSAUTH_SECTION = 'KMS Auth'
KMSAUTH_USEKMSAUTH_OPTION = 'use_kmsauth'
KMSAUTH_USEKMSAUTH_DEFAULT = False

KMSAUTH_KEY_ID_OPTION = 'kmsauth_key_id'
KMSAUTH_KEY_ID_DEFAULT = ''

KMSAUTH_SERVICE_ID_OPTION = 'kmsauth_serviceid'
KMSAUTH_SERVICE_ID_DEFAULT = None

REGION_PASSWORD_OPTION_SUFFIX = '_password'


class BlessConfig(ConfigParser.RawConfigParser):
def __init__(self, aws_region, config_file):
Expand All @@ -48,13 +52,18 @@ def __init__(self, aws_region, config_file):
ENTROPY_MINIMUM_BITS_OPTION: ENTROPY_MINIMUM_BITS_DEFAULT,
RANDOM_SEED_BYTES_OPTION: RANDOM_SEED_BYTES_DEFAULT,
LOGGING_LEVEL_OPTION: LOGGING_LEVEL_DEFAULT,
KMSAUTH_SERVICE_ID_OPTION: KMSAUTH_SERVICE_ID_DEFAULT}
KMSAUTH_SERVICE_ID_OPTION: KMSAUTH_SERVICE_ID_DEFAULT,
KMSAUTH_KEY_ID_OPTION: KMSAUTH_KEY_ID_DEFAULT,
KMSAUTH_USEKMSAUTH_OPTION: KMSAUTH_USEKMSAUTH_DEFAULT}
ConfigParser.RawConfigParser.__init__(self, defaults=defaults)
self.read(config_file)

if not self.has_section(BLESS_OPTIONS_SECTION):
self.add_section(BLESS_OPTIONS_SECTION)

if not self.has_section(KMSAUTH_SECTION):
self.add_section(KMSAUTH_SECTION)

if not self.has_option(BLESS_CA_SECTION, self.aws_region + REGION_PASSWORD_OPTION_SUFFIX):
raise ValueError("No Region Specific Password Provided.")

Expand All @@ -65,12 +74,10 @@ def getpassword(self):
"""
return self.get(BLESS_CA_SECTION, self.aws_region + REGION_PASSWORD_OPTION_SUFFIX)

def getkmsauthkeyid(self):
def getkmsauthkeyids(self):
"""
Returns the correct encrypted password based off of the aws_region.
:return: A Base64 encoded KMS CiphertextBlob.
Returns a list of kmsauth keys used for validation (so a key generated
in one region can validate in another).
:return: A list of kmsauth key id's
"""
config_name = self.aws_region + KMSAUTH_KEY_ID_SUFFIX
if not self.has_option(BLESS_CA_SECTION, config_name):
return KMSAUTH_KEY_ID_DEFAULT
return self.get(BLESS_CA_SECTION, config_name)
return map(str.strip, self.get(KMSAUTH_SECTION, KMSAUTH_KEY_ID_OPTION).split(','))
14 changes: 13 additions & 1 deletion bless/config/bless_deploy_example.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,16 @@ kms_key_id = <alias/key_name>
us-east-1_password = <INSERT_US-EAST-1_KMS_ENCRYPTED_BASE64_ENCODED_PEM_PASSWORD_HERE>
us-west-2_password = <INSERT_US-WEST-2_KMS_ENCRYPTED_BASE64_ENCODED_PEM_PASSWORD_HERE>
# Specify the file name of your SSH CA's Private Key in PEM format.
ca_private_key_file = <INSERT_YOUR_ENCRYPTED_PEM_FILE_NAME>
ca_private_key_file = <INSERT_YOUR_ENCRYPTED_PEM_FILE_NAME>

# This section is optional
[KMS Auth]
# Enable kmsauth, to ensure the certificate's username matches the AWS user
# use_kmsauth = True

# One or multiple KMS keys, setup for kmsauth (see github.com/lyft/python-kmsauth)
# kmsauth_key_id = arn:aws:kms:us-east-1:000000012345:key/eeff5544-6677-8899-9988-aaaabbbbcccc

# If using kmsauth, you need to set the kmsauth service name. Users need to set the 'to'
# context to this same service name when they create a kmsauth token.
# kmsauth_serviceid = bless-production
7 changes: 4 additions & 3 deletions lambda_configs/bless_deploy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ us-east-1_password = AQECAHjLpUgG5RcB4QUEkdSWlKn+EdeCnxJvsmVHf8eNUUt6UAAAAIcwgYQ
us-west-2_password = AQECAHiWyJwSxmh2QoS3OdBq3yohrtz8hO40nlBGgP7CgKA4PAAAAIcwgYQGCSqGSIb3DQEHBqB3MHUCAQAwcAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAyhhI+wL6yfbBXL44MCARCAQ2C+BAYGMejfqpYfbdDHr2OAtPY1gopanOgRMeM299uAVNezaC5496lBncCtcD+p+QXelvf4dCiDI7nJe91Unnvq11Y=
# Specify the file name of your SSH CA's Private Key in PEM format.
ca_private_key_file = bless-ca-lyft
# kmsauth key
us-east-1_kmsauth_key_id = arn:aws:kms:us-east-1:173840052742:key/eef1551a-6643-4cd9-9323-d262079395a1
us-west-2_kmsauth_key_id = arn:aws:kms:us-west-2:173840052742:key/3833941b-cfca-4fb8-a55e-110a523d923a

[KMS Auth]
use_kmsauth = True
# kmsauth key
kmsauth_key_id = arn:aws:kms:us-east-1:173840052742:key/eef1551a-6643-4cd9-9323-d262079395a1, arn:aws:kms:us-west-2:173840052742:key/3833941b-cfca-4fb8-a55e-110a523d923a
# If using kmsauth, you need to set the kmsauth service name (used by the blessclient)
kmsauth_serviceid = bless-production
8 changes: 5 additions & 3 deletions tests/aws_lambda/bless-test-kmsauth.cfg
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
[Bless CA]
ca_private_key_file = ../../tests/aws_lambda/only-use-for-unit-tests.pem
kms_key_id = alias/foo
us-east-1_kmsauth_key_id = alias/authnz-iad
us-west-2_kmsauth_key_id = alias/authnz-sfo
kmsauth_serviceid = kmsauth-prod
us-east-1_password = bogus-password-for-unit-test
us-west-2_password = bogus-password-for-unit-test

[KMS Auth]
use_kmsauth = True
kmsauth_key_id = alias/authnz-iad, alias/authnz-sfo
kmsauth_serviceid = kmsauth-prod

# todo get from config, with some sane defaults
#[loggers]
#keys=root
Expand Down
8 changes: 8 additions & 0 deletions tests/aws_lambda/test_bless_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from bless.aws_lambda.bless_lambda import lambda_handler
from tests.ssh.vectors import EXAMPLE_RSA_PUBLIC_KEY, RSA_CA_PRIVATE_KEY_PASSWORD, \
EXAMPLE_ED25519_PUBLIC_KEY
from kmsauth import TokenValidationError


class Context(object):
Expand Down Expand Up @@ -57,6 +58,13 @@ def test_basic_local_missing_kmsauth_request():
config_file=os.path.join(os.path.dirname(__file__),
'bless-test-kmsauth.cfg'))

def test_invalid_kmsauth_request():
with pytest.raises(TokenValidationError):
cert = lambda_handler(VALID_TEST_REQUEST_KMSAUTH, context=Context,
ca_private_key_password=RSA_CA_PRIVATE_KEY_PASSWORD,
entropy_check=False,
config_file=os.path.join(os.path.dirname(__file__),
'bless-test-kmsauth.cfg'))

def test_local_request_key_not_found():
with pytest.raises(IOError):
Expand Down