Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

distribute via signed s3 urls rather than signed cloudfront urls #204

Draft
wants to merge 1 commit into
base: test
Choose a base branch
from
Draft
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
5 changes: 0 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
domain: grfn.asf.alaska.edu
auth_url: "https://urs.earthdata.nasa.gov/oauth/authorize?response_type=code&client_id=BO_n7nTIlMljdvU6kRRB3g&redirect_uri=https://auth.asf.alaska.edu/login"
jwt_cookie_name: asf-urs
log_bucket: grfn-logs
private_bucket: grfn-content-prod
deploy_ref: refs/heads/prod

Expand All @@ -26,7 +25,6 @@ jobs:
domain: grfn-test.asf.alaska.edu
auth_url: "https://uat.urs.earthdata.nasa.gov/oauth/authorize?client_id=Qkd0Z9KbhG86qedkRC7nSA&response_type=code&redirect_uri=https://auth-test-jenk.asf.alaska.edu/login"
jwt_cookie_name: asf-urs
log_bucket: grfn-logs
private_bucket: grfn-content-test
deploy_ref: refs/heads/test

Expand Down Expand Up @@ -70,11 +68,8 @@ jobs:
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
CertificateArn='${{ secrets.CETRIFICATE_ARN }}' \
CloudFrontKeyPairId='${{ secrets.CLOUDFRONT_KEY_PAIR_ID }}' \
DomainName='${{ matrix.domain }}' \
LogBucket='${{ matrix.log_bucket }}' \
PrivateBucket='${{ matrix.private_bucket }}' \
PrivateKeySecretName='${{ secrets.PRIVATE_KEY_SECRET_NAME }}' \
AuthUrl='${{ matrix.auth_url }}' \
JwtCookieName='${{ matrix.jwt_cookie_name }}' \
JwtPublicKey='${{ secrets.JWT_PUBLIC_KEY }}'
21 changes: 0 additions & 21 deletions cloudformation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,12 @@ Parameters:
Description: Name of S3 bucket in which zipped output products will be archived
Type: String

LogBucket:
Type: String

CertificateArn:
Type: String

DomainName:
Type: String

CloudFrontKeyPairId:
Type: String

PrivateKeySecretName:
Type: String

AuthUrl:
Type: String

Expand All @@ -37,22 +28,10 @@ Resources:
Properties:
Parameters:
Name: !Sub "${AWS::StackName}-door"
CloudFrontDomainName: !GetAtt CloudFrontStack.Outputs.DomainName
CloudFrontKeyPairId: !Ref CloudFrontKeyPairId
PrivateKeySecretName: !Ref PrivateKeySecretName
PrivateBucket: !Ref PrivateBucket
CertificateArn: !Ref CertificateArn
DomainName: !Ref DomainName
AuthUrl: !Ref AuthUrl
JwtCookieName: !Ref JwtCookieName
JwtPublicKey: !Ref JwtPublicKey
TemplateURL: door/cloudformation.yaml

CloudFrontStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
Name: !Ref AWS::StackName
Bucket: !Ref PrivateBucket
LogBucket: !Ref LogBucket
TemplateURL: cloudfront/cloudformation.yaml
83 changes: 0 additions & 83 deletions cloudfront/cloudformation.yaml

This file was deleted.

15 changes: 0 additions & 15 deletions door/cloudformation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ Parameters:
Name:
Type: String

CloudFrontDomainName:
Type: String

CloudFrontKeyPairId:
Type: String

PrivateKeySecretName:
Type: String

PrivateBucket:
Type: String

Expand Down Expand Up @@ -116,9 +107,6 @@ Resources:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*"
- Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${PrivateKeySecretName}*"
- Effect: Allow
Action: s3:ListBucket
Resource: !Sub "arn:aws:s3:::${PrivateBucket}"
Expand All @@ -131,9 +119,6 @@ Resources:
Properties:
Environment:
Variables:
CLOUDFRONT_DOMAIN_NAME: !Ref CloudFrontDomainName
CLOUDFRONT_KEY_PAIR_ID: !Ref CloudFrontKeyPairId
PRIVATE_KEY_SECRET_NAME: !Ref PrivateKeySecretName
EXPIRE_TIME_IN_SECONDS: 15
BUCKET: !Ref PrivateBucket
AUTH_URL: !Ref AuthUrl
Expand Down
3 changes: 1 addition & 2 deletions door/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Flask
Flask-Cors
rsa
serverless_wsgi
PyJWT
cryptography
cryptography
35 changes: 8 additions & 27 deletions door/src/door/routes.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import json
import os
from datetime import datetime, timedelta, timezone
from urllib.parse import quote_plus

import boto3
import jwt
import rsa
from botocore.exceptions import ClientError
from botocore.signers import CloudFrontSigner
from flask import abort, g, redirect, request
from flask_cors import CORS

Expand All @@ -25,12 +21,6 @@ def decode_token(token):
return None


@app.before_first_request
def init_app():
private_key = get_secret(os.environ['PRIVATE_KEY_SECRET_NAME'])['private_key']
os.environ['CLOUDFRONT_PRIVATE_KEY'] = str(private_key)


@app.before_request
def authenticate_user():
cookie = request.cookies.get(os.environ['JWT_COOKIE_NAME'])
Expand All @@ -57,24 +47,15 @@ def download_redirect(object_key):
abort(404)
raise

signed_url = get_signed_url(object_key, g.user_id, os.environ['CLOUDFRONT_PRIVATE_KEY'])
signed_url = get_signed_url(object_key, g.user_id)
return redirect(signed_url)


def get_signed_url(object_key, user_id, private_key):
def rsa_signer(message):
key = rsa.PrivateKey.load_pkcs1(private_key.encode(), 'PEM')
return rsa.sign(message, key, 'SHA-1')

base_url = f'https://{os.environ["CLOUDFRONT_DOMAIN_NAME"]}/{object_key}?userid={user_id}'
expiration_datetime = datetime.now(tz=timezone.utc) + timedelta(seconds=int(os.environ['EXPIRE_TIME_IN_SECONDS']))
cf_signer = CloudFrontSigner(os.environ['CLOUDFRONT_KEY_PAIR_ID'], rsa_signer)
signed_url = cf_signer.generate_presigned_url(base_url, date_less_than=expiration_datetime)
def get_signed_url(object_key, user_id):
signed_url = s3.generate_presigned_url(
ClientMethod='get_object',
Params={'Bucket': os.environ['BUCKET'], 'Key': object_key},
ExpiresIn=int(os.environ['EXPIRE_TIME_IN_SECONDS']),
)
signed_url += f'&user_id={user_id}'
return signed_url


def get_secret(secret_name):
sm = boto3.client('secretsmanager', os.environ['AWS_REGION'])
response = sm.get_secret_value(SecretId=secret_name)
secret = json.loads(response['SecretString'])
return secret