亚马逊CloudFront的创建签名饼干 [英] Creating Signed Cookies for Amazon CloudFront

查看:356
本文介绍了亚马逊CloudFront的创建签名饼干的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

亚马逊已经推出了的Cloudfront签署最近除了标识的URL的cookie。

Amazon has introduced Cloudfront signed cookie recently in addition to signed url.

有一个类似的quesition已经了解签署网址。显然存在对在CloudFront的SDK

A similar quesition has been about signed url. Apparently there is support for signed url in the cloudfront SDK

不过,我无法找到在AWS的Python SDK此功能的支持。

However I cannot find the support of this feature in the aws python SDK.

我怎么能搞到要创建签名的cookie?

How can I got about to create a signed cookie?

推荐答案

我创建了一个博托功能要求增加这一点,但在此期间,我得到了它与我的Django的Python应用程序的工作。下面是我从我自己的泛型简单code。在底部是一个简单的Django视图的方法,所以你可以看到我是如何设置cookie包含的Cloudfront内容的网页。

I created a boto feature request to add this, but in the meantime I got it working with my django python app. Here's simple code that I've generified from my own. At the bottom is a sample django view method so you can see how I set cookies for a web page containing Cloudfront content.

import time
from boto.cloudfront import CloudFrontConnection
from boto.cloudfront.distribution import Distribution
from config import settings
import logging
from django.template.context import RequestContext
from django.shortcuts import render_to_response
logger = logging.getLogger('boto')
logger.setLevel(logging.CRITICAL) #disable DEBUG logging that's enabled in AWS by default (outside of django)

AWS_ACCESS_KEY="AKABCDE1235ABCDEF22A"#SAMPLE
AWS_SECRET_KEY="a1wd2sD1A/GS8qggkXK1u8kHlh+BiLp0C3nBJ2wW" #SAMPLE
key_pair_id="APKABCDEF123ABCDEFAG" #SAMPLE
DOWNLOAD_DIST_ID = "E1ABCDEF3ABCDE" #SAMPLE replace with the ID of your Cloudfront dist from Cloudfront console

############################################
def generate_signed_cookies(resource,expire_minutes=5):
    """
    @resource   path to s3 object inside bucket(or a wildcard path,e.g. '/blah/*' or  '*')
    @expire_minutes     how many minutes before we expire these access credentials (within cookie)
    return tuple of domain used in resource URL & dict of name=>value cookies
    """
    if not resource:
        resource = 'images/*'
    dist_id = DOWNLOAD_DIST_ID
    conn = CloudFrontConnection(AWS_ACCESS_KEY, AWS_SECRET_KEY)
    dist = SignedCookiedCloudfrontDistribution(conn,dist_id)
    return dist.create_signed_cookies(resource,expire_minutes=expire_minutes)

############################################
class SignedCookiedCloudfrontDistribution():

    def __init__(self,connection,download_dist_id,cname=True):
        """
        @download_dist_id   id of your Cloudfront download distribution
        @cname          boolean True to use first domain cname, False to use 
                        cloudfront domain name, defaults to cname
                        which presumably matches your writeable cookies ( .mydomain.com)
        """
        self.download_dist = None
        self.domain = None
        try:
            download_dist = connection.get_distribution_info(download_dist_id)
            if cname and download_dist.config.cnames:
                self.domain = download_dist.config.cnames[0] #use first cname if defined
            else:
                self.domain = download_dist.domain_name
            self.download_dist = download_dist
        except Exception, ex:
            logging.error(ex)

    def get_http_resource_url(self,resource=None,secure=False):
        """
        @resource   optional path and/or filename to the resource 
                   (e.g. /mydir/somefile.txt);
                    defaults to wildcard if unset '*'
        @secure     whether to use https or http protocol for Cloudfront URL - update  
                    to match your distribution settings 
        return constructed URL
        """
        if not resource:
            resource = '*'
        protocol = "http" if not secure else "https"
        http_resource = '%s://%s/%s' % (protocol,self.domain,resource)
        return http_resource

    def create_signed_cookies(self,resource,expire_minutes=3):
        """
        generate the Cloudfront download distirbution signed cookies
        @resource   path to the file, path, or wildcard pattern to generate policy for
        @expire_minutes  number of minutes until expiration
        return      tuple with domain used within policy (so it matches 
                    cookie domain), and dict of cloudfront cookies you
                    should set in request header
        """
        http_resource = self.get_http_resource_url(resource,secure=False)    #per-file access #NOTE secure should match security settings of cloudfront distribution
    #    http_resource = self.get_http_resource_url("somedir/*")  #blanket access to all /somedir files inside my bucket
    #    http_resource = self.get_http_resource_url("*")          #blanket access to all files inside my bucket

        #generate no-whitespace json policy, then base64 encode & make url safe
        policy = Distribution._canned_policy(http_resource,SignedCookiedCloudfrontDistribution.get_expires(expire_minutes))
        encoded_policy = Distribution._url_base64_encode(policy)

        #assemble the 3 Cloudfront cookies
        signature = SignedCookiedCloudfrontDistribution.generate_signature(policy,private_key_file=settings.AMAZON_PRIV_KEY_FILE)
        cookies = {
            "CloudFront-Policy" :encoded_policy,
            "CloudFront-Signature" :signature,
            "CloudFront-Key-Pair-Id" :key_pair_id #e.g, APKA..... -> same value you use when you sign URLs with boto distribution.create_signed_url() function
        }
        return self.domain,cookies

    @staticmethod
    def get_expires(minutes):
        unixTime = time.time() + (minutes * 60)
        expires = int(unixTime)  #if not converted to int causes Malformed Policy error and has 2 decimals in value
        return expires

    @staticmethod
    def generate_signature(policy,private_key_file=None):
        """
        @policy     no-whitespace json str (NOT encoded yet)
        @private_key_file   your .pem file with which to sign the policy
        return encoded signature for use in cookie
        """
        #sign the policy - code borrowed from Distribution._create_signing_params()
        signature = Distribution._sign_string(policy, private_key_file)
        #now base64 encode the signature & make URL safe
        encoded_signature = Distribution._url_base64_encode(signature)
        return encoded_signature

############################################
def sample_django_view_method(request,template="mytemplate.html"):
    expireLen = 30 #30 minutes
    s3resource = "somepath_in_my_bucket/afile.mp4"
    context = {} #variables I'm passing to my html template
    response = render_to_response(template, context, context_instance=RequestContext(request))
    domain,cookies = generate_signed_cookies(s3resource,expire_minutes=expireLen)
    #TROUBLESHOOTING COOKIES:
    #NOTE - Cookie Domain must be a domain you control that spans your app & your Cloudfront CNAME
    #NOTE - (e.g. if my webapp is www.mydomain.com and my AWS Download Distribution has cname cloud.mydomain.com, cant set cookies from webapp to 
            # www.mydomain.com or localhost.mydomain.com or cloud.mydomain.com and have them work 
        # -> instead set cookies to .mydomain.com to work across sub-domains, you can then verify in request headers to CloudFront that these cookies get passed.
        # TIP - if you set_cookies from a page with a .mydomain.com suffix, but don't see them get set in Chrome they didn't get set because of permissions - can't set to a diff subdomain or diff base domain
        # TIP - if you set_cookies and see them in Chrome but don't see them in request headers to Cloudfront, cookie domain is likely too narrow, need to widen to span subdomains
    base_domain = '.mydomain.com'
    # NOTE: Sanity check when testing so you can flag any gotchas - I have not fully tested using non-cname urls inside policy vs all possible domains for cookie itself   
    if not domain.endswith(base_domain):
        logger.warn("This likely won't work - your resource permissions use a different domain than your cookies")
    for name,value in cookies.items():
        response.set_cookie(name,value=value,httponly=True,domain=base_domain)
    return response

############################################

if __name__ == '__main__':
    domain,cookies = generate_signed_cookies('images/*',expire_minutes=30)

我的设置注意事项:

Notes about my setup:

  • 我只作一个改变一个已经设定与我的下载分发;工作签网址:我不得不添加一个CNAME与基础域匹配我的网站。
  • 我用的是Chrome浏览器的Web开发工具:

  • I had to make only one change to my download distribution that was already set up & working for signed URLs: I had to add a cname with a base domain matching my website.
  • I used the Chrome Web Developer tools:

  • 网络:以查看CloudFront的呼叫发送请求头,看403 VS 200 /状态/响应大小
  • 控制台:看到403错误,直到我得到了一切工作
  • 资源>饼干 - 验证[本地主机或主机] .mydomain.com饼干显示填充3的Cloudfront饼干,它们被设置为域= .mydomain.com,这些值匹配的值在请求标头CloudFront的(如果丢失,有可能域配置错误)

我的AWS配置

  • 在S3需要的Cloudfront原产地
  • 的Cloudfront下载分发:
    • 分发设置:
      • CNAME定义:cloud.mydomain.com(NEW!对我来说)
      • 在默认的Cloudfront证书
      • S3 requires Cloudfront origin
      • Cloudfront download distribution:
        • Distribution Settings:
          • cname defined: cloud.mydomain.com (NEW FOR ME!)
          • Default Cloudfront certificate
          • 所有这些都来自我已经使用的URL签署的设置不变
          • 在HTTP和HTTPS
          • GET,HEAD
          • 转发标题:无
          • 使用产地缓存头
          • 最小TTL:0
          • 转发饼干:无
          • 转发查询字符串:否
          • 平滑流:没有
          • 在限制浏览器访问:YES(自签署的网址没有变化)
          • 信任的签名者:自我
          • All of these are unchanged from the settings I already used with signed URLs
          • HTTP and HTTPS
          • GET,HEAD
          • Forward Headers: None
          • Use Origin Cache Headers
          • Minimum TTL: 0
          • Forward Cookies: None
          • Forward QueryStrings: No
          • Smooth Streaming: No
          • Restrict Viewer Access: YES (NO CHANGE since signed urls)
          • Trusted Signers: Self

          最棘手的部分,一旦你有饼干产生code以上:

          Trickiest parts once you have the cookie-generating code above:

          • 确保cookie的访问权
          • 确保路径/资源的政策正在从你的应用程序相匹配的要求

          这篇关于亚马逊CloudFront的创建签名饼干的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆