Reputation: 347
I want to serve static files, images specifically, for my flask app on heroku using a private S3 bucket.
I created a pre-signed url using boto3 with the access key ID and secret key of an IAM user with permissions. I used that url as the src for the img in my html file.
I looked at the url that it generates and it displays the bucket name and the access key id for that IAM user. Is this a security issue?
On AWS it says to "Manage your access keys as securely as you do your user name and password." Is there a better way to do this that protects the access key id? (if it needs protecting) I've seen some sites that have these openly displayed and I'm mostly following examples from AWS but I just want to be sure.
Data is stored in environment variables.
import os
import boto3
from flask import Flask, render_template
SECRET_KEY = os.environ["AWS_SECRET_ACCESS_KEY"]
ACCESS_ID = os.environ["AWS_ACCESS_KEY_ID"]
bucket = os.environ["AWS_STORAGE_BUCKET_NAME"]
key = "default_banner"
s3 = boto3.client("s3", aws_secret_access_key=SECRET_KEY, aws_access_key_id=ACCESS_ID)
app = Flask(__name__)
@app.route("/")
def index():
context = {"s3": s3, "bucket": bucket, "key": key}
return render_template("index.html", **context)
if __name__ == "__main__":
app.run()
Here's the import part of the rendered template: templates/index.html
...
<img src="{{ s3.generate_presigned_url('get_object', Params={'Bucket': bucket, 'Key': key}) }}" alt="...">
...
When I inspect the image on the page to see what jinja2 converted it into, I see something like
...
<img src="https://bucket-name.s3.amazonaws.com/default_banner?AWSAccessKeyId=AKIAIDEXAMPLE4AWSID&Signature=h67g7v6aC65aca7YPHcQVbXgt8M%3D&Expires=1566073856" alt="...">
...
Upvotes: 8
Views: 6501
Reputation: 179194
"Manage your access keys as securely as you do your user name and password."
Your username isn't typically a secret, and the same thing goes for the AWS Access Key ID.
The sensitive value is the access key secret. Both values are useless without the other, but the model is designed to treat the ID (the value starting with AKIA
) as the non-sensitive value of the two. Exposing these in signed URLs is acceptable.
The signature also isn't sensitive, since it is not computationally feasible to reconstruct the secret key from the information embedded in a signed URL... but the signature also does not contain enough information for the service to be able to determine who tried to authorize the request... which is why the Access Key ID is included in the signed URL.
In fact, to be precise, the signature doesn't really contain any information at all. The service, internally, looks up your secret key from the provided access key ID and regenerates the same signed URL using your credentials. If it gets the same answer as provided in the URL's signature, the request is valid, otherwise the request is rejected.
Upvotes: 16