"""Model representation of temporary AWS token.""" import json from botocore.exceptions import ClientError from podcast import config from podcast.connectors import sts from podcast.constants import api as api_const from podcast.utils.exc import OwsError def _to_dict(sts_response): """Format boto3 sts client response. Args: sts_response (dict): boto3 response. Returns: dict: our convention for an AWS token. """ credentials = sts_response['Credentials'] return { 'token': credentials['SessionToken'], 'aws_access_key_id': credentials['AccessKeyId'], 'aws_secret_access_key': credentials['SecretAccessKey'], 'expiration': str(credentials['Expiration']) } def _prepare_iam_policy_s3(bucket, filename): """Modify the IAM policy to limit uploads to bucket and filename. Args: filename: Name of the file to put. Returns: dict: The IAM policy """ resource = 'arn:aws:s3:::{bucket}/{filename}.*'.format(bucket=bucket, filename=filename) return { 'Version': '2012-10-17', 'Statement': [ { 'Effect': 'Allow', 'Action': [ 's3:PutObject', 's3:PutObjectAcl', 's3:PutObjectTagging', 's3:PutObjectVersionAcl', 's3:PutObjectVersionTagging', ], 'Resource': resource } ] } def get_s3_token(filename): """Generate session token for S3 Upload. Args: filename (string): Name of the file, sans extension to be uploaded. Returns: dict: a dict containing credentials. """ sts_client = sts.get_sts_client() if not sts_client: raise OwsError('sts_unavailable') try: policy = _prepare_iam_policy_s3( '{}/{}'.format(config.OUTPUT_ASSETS_BUCKET_NAME, api_const.ADUPLOAD_PATH), filename) sts_response = sts_client.assume_role( RoleArn=config.UPLOAD_ROLE_ARN, RoleSessionName=filename, DurationSeconds=3600, # 1 hour Policy=json.dumps(policy) ) return _to_dict(sts_response) except ClientError as error: raise OwsError.from_boto3_client_error(error, 'Error generating upload token')