{ "info": { "author": "karmafeast", "author_email": "karmafeast@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# Custom::CFrontDistro\n\n## USE\n\nUse this custom resource as if a regular AWS::CloudFront::Distribution, with additional syntax available for the configuration and use of origin groups (see below section)\n\nNative AWS::CloudFront::Distribution documentation implies (correctly in this case) that an origin group can be used in cache behaviors / default cache behavior as the target origin.\n\nWhile this is true in this custom resource, there is no ability to create an origin group in the native resource (10/2019).\nRegardless of the documentation state at AWS - you can do as it says with this resource.\n\n## Method of Operation\n\nA cloudformation custom resource for CloudFront distributions is lifecycle managed by an associated lambda function in this instance.\n\nThis function must exist for the custom resource to be able to be created, and its ARN must be referenced in the custom resource declaration in its 'ServiceToken' property\n\n```JSON\n{\n...\n {\"MyDistro\":\n \"Type\": \"Custom::CFrontDistro\",\n {\"Properties\":\n {\n \"ServiceToken\":\"ARN_TO_FUNCTION\",\n \"DistributionConfig\": {\"keys\": \"values\"}\n }\n }\n }\n}\n```\n\n## New things in the distribution config\n\nYou may specify origin groups in a form that should appear familiar to those using cloudformation.\n\n\n### OriginGroups list (of dict items) --\nA complex type that contains information about origin groups for this distribution.\n\n### OriginGroups list item(dict) --\nAn origin group includes two origins (a primary origin and a second origin to failover to) and a failover criteria that you specify. \n\nNOTE - the FIRST ITEM in the list of 'Members' will be the primary origin of the pair.\n\nYou create an origin group to support origin failover in CloudFront. \n\nWhen you create or update a distribution, you can specify the origin group instead of a single origin, and CloudFront will failover \nfrom the primary origin to the second origin under the failover conditions that you've chosen.\n\n### Id (string) -- [REQUIRED]\nThe origin group's ID. This is a string, and one that should match cache behavior entries where this origin group is referenced\n\n### FailoverCriteria (dict) -- [REQUIRED]\nA complex type that contains information about the failover criteria for an origin group.\n\n### StatusCodes (list) -- [REQUIRED]\nThe status codes that, when returned from the primary origin, will trigger CloudFront to failover to the second origin.\nThe StatusCodes list is the FailoverCriteria dict (see examples). \nthese are integer numbers for the 400/500 HTTPStatus codes that invoke failover in the origin group.\n\n### Members (list) -- [REQUIRED]\nA complex type that contains information about the origins in an origin group.\n\nNOTE - the FIRST ITEM in the list of 'Members' will be the primary origin of the pair.\n\nNOTE - the 'ID' of the member origin group should be used. These should be specified elsewhere in the distribution config as normal.\n\n~~~YAML\nAWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\nDescription: Custom Resource for CloudFront Distribution, supporting origin groups\nResources:\n CustomCFrontDistro:\n Type: Custom::CFrontDistro\n Properties:\n ServiceToken:\n Fn::ImportValue: CustomCFrontDistributionFunctionARN\n DistributionConfig:\n#...\n OriginGroups:\n - Id: testyorigingroup\n FailoverCriteria:\n StatusCodes:\n - 403\n - 404\n - 500\n - 502\n - 503\n - 504\n Members:\n - my_fake_origin_1\n - my_fake_origin_2\n CustomErrorResponses:\n - ErrorCode: 403\n ResponsePagePath: \"/some/path/to/here\"\n ResponseCode: 200\n ErrorCachingMinTTL: 999\n#... rest of distribution config\n~~~\n\n~~~JSON\n{\n \"OriginGroups\":[\n {\n \"Id\":\"testyorigingroup\",\n \"FailoverCriteria\":{\n \"StatusCodes\":[\n 403,\n 404,\n 500,\n 502,\n 503,\n 504\n ]\n },\n \"Members\":[\n \"my_fake_origin_1\",\n \"my_fake_origin_2\"\n ]\n }\n ],\n \"CustomErrorResponses\":[\n {\n \"ErrorCode\":403,\n \"ResponsePagePath\":\"/some/path/to/here\",\n \"ResponseCode\":200,\n \"ErrorCachingMinTTL\":999\n }\n ]\n}\n~~~\n\n## How to Deploy the Custom Resource Lambda\n\nYour ```Custom::CFrontDistro``` containing template must have a 'ServiceToken' property, which is the ARN to the lambda function which manages\nthe custom resource lifecycle.\n\nThere are two ways you could achieve this.\n\n### 1. deploy the function as a separate stack, export its ARN in the template. Import that exported ARN value into template where resource is used.\n\nThis method is preferred if you wish to have a single cloudwatch log stream to examine for the resource lambda actions in a given account, rather than\nthe second method, which will deploy a lambda function independently in each template where it is used.\n\nYou will get better debug using this method - as if there is failure in a template where the function itself is a resource, it will be purged along with\nthe rest of the stack if creation fails.\n\n### 2. deploy the function and the resource together in a single template - elect not to reuse the resource lambda\n\nMore portable in some regards, in that you don't end up referencing a cfn export to locate the ARN of the custom resource function\n\nFragmented logging, overdeployment of lambda functions (per template vs shared per account).\n\nTighter permission control is possible if you deploy with the resource to manage a sinlge distro, in that you can restrict things like s3 bucket acl get/put to target distro\naccess logging bucket.\n\n### Notes on IAM Permissions for Custom Resource Function\n\nShown in Examples section below.\n\nRemember, the resource creations are occurring with the lambda execution context - NOT whatever is running the CloudFormation template.\n\nTo this end, the lambda execution will require full ability to manage CloudFront resources.\n\nSimilarly it will require access to CloudWatch to configure events for its own execution, and for options that might be specified in a resource.\n\nThe role will also require ability to list all s3 buckets, and to get/set acls on buckets - to support configuration of resources that elect to include\nlogging.\n\nTo support polling for long operations in cloudformation associated with cloudfront distros (a create or update can take many minutes to return),\nthe lambda function does not attempt to wait for readieness of a managed resource before returning.\n\nInstead it sets up polling of itself and the lambda function handler routes events based on their type from cloudformation (e.g. poll_update).\nThere is a return format which allows cloudformation to poll for a resource's change to desired state 'SUCCESS' following a configuration change.\n\n## Examples\n\n### Lambda Function for Custom Resource\n\n~~~YAML\n---\nAWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\nDescription: Custom Resource for CloudFront Distribution, supporting origin groups\nResources:\n CustomCFrontDistributionFunction:\n Type: AWS::Serverless::Function\n Properties:\n CodeUri: customCFrontDistro/\n Handler: customCFrontDistro.lambda_handler\n Runtime: python3.7\n Role:\n Fn::GetAtt:\n - IARCustomCFrontDistribution\n - Arn\n Timeout: 300\n IARCustomCFrontDistribution:\n Type: AWS::IAM::Role\n Properties:\n ManagedPolicyArns:\n - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\n - arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess\n - arn:aws:iam::aws:policy/CloudFrontFullAccess\n - arn:aws:iam::aws:policy/CloudWatchEventsFullAccess\n AssumeRolePolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Action:\n - sts:AssumeRole\n Effect: Allow\n Principal:\n Service:\n - lambda.amazonaws.com\n IAMPS3Policy:\n Type: AWS::IAM::ManagedPolicy\n Properties:\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Action:\n - s3:ListAllMyBuckets\n - s3:GetBucketAcl\n - s3:PutBucketAcl\n Resource: \"*\"\n Roles:\n - Ref: IARCustomCFrontDistribution\n IAMPLambdaPerms:\n Type: AWS::IAM::ManagedPolicy\n Properties:\n PolicyDocument:\n Version: '2012-10-17'\n Statement:\n - Effect: Allow\n Action:\n - lambda:AddPermission\n - lambda:RemovePermission\n - events:PutRule\n - events:DeleteRule\n - events:PutTargets\n - events:RemoveTargets\n Resource:\n Fn::GetAtt:\n - CustomCFrontDistributionFunction\n - Arn\n Roles:\n - Ref: IARCustomCFrontDistribution\nOutputs:\n CustomCFrontDistributionFunctionARN:\n Description: Custom CFront Distribution Lambda Function ARN\n Value:\n Fn::GetAtt:\n - CustomCFrontDistributionFunction\n - Arn\n Export:\n Name: CustomCFrontDistributionFunctionARN\n\n~~~\n\n~~~JSON\n{\n \"AWSTemplateFormatVersion\":\"2010-09-09\",\n \"Transform\":\"AWS::Serverless-2016-10-31\",\n \"Description\":\"Custom Resource for CloudFront Distribution, supporting origin groups\",\n \"Resources\":{\n \"CustomCFrontDistributionFunction\":{\n \"Type\":\"AWS::Serverless::Function\",\n \"Properties\":{\n \"CodeUri\":\"customCFrontDistro/\",\n \"Handler\":\"customCFrontDistro.lambda_handler\",\n \"Runtime\":\"python3.7\",\n \"Role\":{\n \"Fn::GetAtt\":[\n \"IARCustomCFrontDistribution\",\n \"Arn\"\n ]\n },\n \"Timeout\":300\n }\n },\n \"IARCustomCFrontDistribution\":{\n \"Type\":\"AWS::IAM::Role\",\n \"Properties\":{\n \"ManagedPolicyArns\":[\n \"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole\",\n \"arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess\",\n \"arn:aws:iam::aws:policy/CloudFrontFullAccess\",\n \"arn:aws:iam::aws:policy/CloudWatchEventsFullAccess\"\n ],\n \"AssumeRolePolicyDocument\":{\n \"Version\":\"2012-10-17\",\n \"Statement\":[\n {\n \"Action\":[\n \"sts:AssumeRole\"\n ],\n \"Effect\":\"Allow\",\n \"Principal\":{\n \"Service\":[\n \"lambda.amazonaws.com\"\n ]\n }\n }\n ]\n }\n }\n },\n \"IAMPS3Policy\":{\n \"Type\":\"AWS::IAM::ManagedPolicy\",\n \"Properties\":{\n \"PolicyDocument\":{\n \"Version\":\"2012-10-17\",\n \"Statement\":[\n {\n \"Effect\":\"Allow\",\n \"Action\":[\n \"s3:ListAllMyBuckets\",\n \"s3:GetBucketAcl\",\n \"s3:PutBucketAcl\"\n ],\n \"Resource\":\"*\"\n }\n ]\n },\n \"Roles\":[\n {\n \"Ref\":\"IARCustomCFrontDistribution\"\n }\n ]\n }\n },\n \"IAMPLambdaPerms\":{\n \"Type\":\"AWS::IAM::ManagedPolicy\",\n \"Properties\":{\n \"PolicyDocument\":{\n \"Version\":\"2012-10-17\",\n \"Statement\":[\n {\n \"Effect\":\"Allow\",\n \"Action\":[\n \"lambda:AddPermission\",\n \"lambda:RemovePermission\",\n \"events:PutRule\",\n \"events:DeleteRule\",\n \"events:PutTargets\",\n \"events:RemoveTargets\"\n ],\n \"Resource\":{\n \"Fn::GetAtt\":[\n \"CustomCFrontDistributionFunction\",\n \"Arn\"\n ]\n }\n }\n ]\n },\n \"Roles\":[\n {\n \"Ref\":\"IARCustomCFrontDistribution\"\n }\n ]\n }\n }\n },\n \"Outputs\":{\n \"CustomCFrontDistributionFunctionARN\":{\n \"Description\":\"Custom CFront Distribution Lambda Function ARN\",\n \"Value\":{\n \"Fn::GetAtt\":[\n \"CustomCFrontDistributionFunction\",\n \"Arn\"\n ]\n },\n \"Export\":{\n \"Name\":\"CustomCFrontDistributionFunctionARN\"\n }\n }\n }\n}\n~~~\n\n\n### Resource use example\n\n~~~YAML\n---\nAWSTemplateFormatVersion: '2010-09-09'\nTransform: AWS::Serverless-2016-10-31\nDescription: Custom Resource for CloudFront Distribution, supporting origin groups\nResources:\n CustomCFrontDistro:\n Type: Custom::CFrontDistro\n Properties:\n ServiceToken:\n Fn::ImportValue: CustomCFrontDistributionFunctionARN\n DistributionConfig:\n Comment: i am not real, only testy!\n Logging:\n Bucket: fake_name_thing.s3.amazonaws.com\n Enabled: true\n Restrictions:\n GeoRestriction:\n RestrictionType: none\n Quantity: 0\n ViewerCertificate:\n CloudFrontDefaultCertificate: true\n CacheBehaviors:\n - AllowedMethods:\n - GET\n - HEAD\n CachedMethods:\n - GET\n - HEAD\n Compress: false\n ForwardedValues:\n QueryString: false\n PathPattern: \"*.hugwolf\"\n TargetOriginId: testyorigingroup\n ViewerProtocolPolicy: https-only\n - Compress: false\n DefaultTTL: 600\n ForwardedValues:\n QueryString: false\n PathPattern: \"*.fake_name_thing\"\n TargetOriginId: testyorigingroup\n ViewerProtocolPolicy: https-only\n DefaultCacheBehavior:\n TargetOriginId: my_fake_origin_1\n ViewerProtocolPolicy: https-only\n ForwardedValues:\n QueryString: false\n HttpVersion: http2\n Origins:\n - Id: my_fake_origin_1\n DomainName: my_fake_origin_1.s3.amazonaws.com\n S3OriginConfig:\n OriginAccessIdentity: origin-access-identity/cloudfront/E_FAKE_ORIGIN_ACCESS_ID_1\n - Id: my_fake_origin_2\n DomainName: my_fake_origin_2.s3.amazonaws.com\n S3OriginConfig:\n OriginAccessIdentity: origin-access-identity/cloudfront/E_FAKE_ORIGIN_ACCESS_ID_2\n OriginGroups:\n - Id: testyorigingroup\n FailoverCriteria:\n StatusCodes:\n - 403\n - 404\n - 500\n - 502\n - 503\n - 504\n Members:\n - my_fake_origin_1\n - my_fake_origin_2\n CustomErrorResponses:\n - ErrorCode: 403\n ResponsePagePath: \"/some/path/to/here\"\n ResponseCode: 200\n ErrorCachingMinTTL: 999\nOutputs:\n customCFrontDistroDomainName:\n Description: cloudfront distribution domain name\n Value:\n Fn::GetAtt:\n - CustomCFrontDistro\n - DomainName\n customCFrontDistroARN:\n Description: cloudfront distribution ARN\n Value:\n Fn::GetAtt:\n - CustomCFrontDistro\n - ARN\n\n~~~\n\n~~~JSON\n \"Resources\":{\n \"CustomCFrontDistro\":{\n \"Type\":\"Custom::CFrontDistro\",\n \"Properties\":{\n \"ServiceToken\": {\"Fn::ImportValue\": \"CustomCFrontDistributionFunctionARN\"},\n \"DistributionConfig\":{\n \"Comment\":\"i am not real, only testy!\",\n \"Logging\":{\n \"Bucket\":\"fake_name_thing.s3.amazonaws.com\"\n },\n \"Enabled\":true,\n \"Restrictions\":{\n \"GeoRestriction\":{\n \"RestrictionType\":\"none\",\n \"Quantity\":0\n }\n },\n \"ViewerCertificate\":{\n \"CloudFrontDefaultCertificate\":true\n },\n \"CacheBehaviors\":[\n {\n \"AllowedMethods\":[\n \"GET\",\n \"HEAD\"\n ],\n \"CachedMethods\":[\n \"GET\",\n \"HEAD\"\n ],\n \"Compress\":false,\n \"ForwardedValues\":{\n \"QueryString\":false\n },\n \"PathPattern\":\"*.hugwolf\",\n \"TargetOriginId\":\"testyorigingroup\",\n \"ViewerProtocolPolicy\":\"https-only\"\n },\n {\n \"Compress\":false,\n \"DefaultTTL\":600,\n \"ForwardedValues\":{\n \"QueryString\":false\n },\n \"PathPattern\":\"*.fake_name_thing\",\n \"TargetOriginId\":\"testyorigingroup\",\n \"ViewerProtocolPolicy\":\"https-only\"\n }\n ],\n \"DefaultCacheBehavior\":{\n \"TargetOriginId\":\"my_fake_origin_1\",\n \"ViewerProtocolPolicy\":\"https-only\",\n \"ForwardedValues\":{\n \"QueryString\":false\n }\n },\n \"HttpVersion\":\"http2\",\n \"Origins\":[\n {\n \"Id\":\"my_fake_origin_1\",\n \"DomainName\":\"my_fake_origin_1.s3.amazonaws.com\",\n \"S3OriginConfig\":{\n \"OriginAccessIdentity\":\"origin-access-identity/cloudfront/E_FAKE_ORIGIN_ACCESS_ID_1\"\n }\n },\n {\n \"Id\":\"my_fake_origin_2\",\n \"DomainName\":\"my_fake_origin_2.s3.amazonaws.com\",\n \"S3OriginConfig\":{\n \"OriginAccessIdentity\":\"origin-access-identity/cloudfront/E_FAKE_ORIGIN_ACCESS_ID_2\"\n }\n }\n ],\n \"OriginGroups\":[\n {\n \"Id\":\"testyorigingroup\",\n \"FailoverCriteria\":{\n \"StatusCodes\":[\n 403,\n 404,\n 500,\n 502,\n 503,\n 504\n ]\n },\n \"Members\":[\n \"my_fake_origin_1\",\n \"my_fake_origin_2\"\n ]\n }\n ],\n \"CustomErrorResponses\":[\n {\n \"ErrorCode\":403,\n \"ResponsePagePath\":\"/some/path/to/here\",\n \"ResponseCode\":200,\n \"ErrorCachingMinTTL\":999\n }\n ]\n }\n }\n }\n },\n \"Outputs\": {\n \"customCFrontDistroDomainName\": {\n \"Description\": \"cloudfront distribution domain name\",\n \"Value\": {\n \"Fn::GetAtt\": [\n \"CustomCFrontDistro\",\n \"DomainName\"\n ]\n }\n },\n \"customCFrontDistroARN\": {\n \"Description\": \"cloudfront distribution ARN\",\n \"Value\": {\n \"Fn::GetAtt\": [\n \"CustomCFrontDistro\",\n \"ARN\"\n ]\n }\n }\n }\n~~~\n\n## ref\n[cfn: AWS::CloudFront::Distribution](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html \"cfn: AWS::CloudFront::Distribution\")\n\n[boto3 docs for CFront](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#CloudFront.Client.create_distribution \"this is cfn data is translated into and from\")\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/karmafeast/CfnCustomCFrontDistro", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "CfnCustomCFrontDistro", "package_url": "https://pypi.org/project/CfnCustomCFrontDistro/", "platform": "", "project_url": "https://pypi.org/project/CfnCustomCFrontDistro/", "project_urls": { "Homepage": "https://github.com/karmafeast/CfnCustomCFrontDistro" }, "release_url": "https://pypi.org/project/CfnCustomCFrontDistro/0.0.1/", "requires_dist": [ "boto3 (>=1.9.189)", "botocore (>=1.12.189)", "crhelper (>=2.0.4)", "pytest (>=5.0.1)", "str2bool (>=1.1)" ], "requires_python": ">=3.7", "summary": "AWS cloudformation CloudFront Distributions with OriginGroups support", "version": "0.0.1", "yanked": false, "yanked_reason": null }, "last_serial": 6053989, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "769659256741e938f748b0fd587d2a4b", "sha256": "5bc90c3b77c2b2c202ba13440ab5c3b28e63262320afd3937435461e85d02df3" }, "downloads": -1, "filename": "CfnCustomCFrontDistro-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "769659256741e938f748b0fd587d2a4b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 23224, "upload_time": "2019-10-30T17:52:55", "upload_time_iso_8601": "2019-10-30T17:52:55.194782Z", "url": "https://files.pythonhosted.org/packages/58/16/247b7abf4c27b83935b14b0ae68f9941c1f3562c07b1a7a6f514c60c0d4c/CfnCustomCFrontDistro-0.0.1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "696a08af6f9ab617cc5c5bcb38bf7be3", "sha256": "207627215ce5393ff5216af6ae783f8c69c3becbf381023318b16f75829387ce" }, "downloads": -1, "filename": "CfnCustomCFrontDistro-0.0.1.tar.gz", "has_sig": false, "md5_digest": "696a08af6f9ab617cc5c5bcb38bf7be3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 29152, "upload_time": "2019-10-30T17:52:57", "upload_time_iso_8601": "2019-10-30T17:52:57.482783Z", "url": "https://files.pythonhosted.org/packages/28/aa/28f2d1f378bd74a38ef97bbb04f6db71716d1cad87d854a68f28bd101be6/CfnCustomCFrontDistro-0.0.1.tar.gz", "yanked": false, "yanked_reason": null } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "769659256741e938f748b0fd587d2a4b", "sha256": "5bc90c3b77c2b2c202ba13440ab5c3b28e63262320afd3937435461e85d02df3" }, "downloads": -1, "filename": "CfnCustomCFrontDistro-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "769659256741e938f748b0fd587d2a4b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 23224, "upload_time": "2019-10-30T17:52:55", "upload_time_iso_8601": "2019-10-30T17:52:55.194782Z", "url": "https://files.pythonhosted.org/packages/58/16/247b7abf4c27b83935b14b0ae68f9941c1f3562c07b1a7a6f514c60c0d4c/CfnCustomCFrontDistro-0.0.1-py3-none-any.whl", "yanked": false, "yanked_reason": null }, { "comment_text": "", "digests": { "md5": "696a08af6f9ab617cc5c5bcb38bf7be3", "sha256": "207627215ce5393ff5216af6ae783f8c69c3becbf381023318b16f75829387ce" }, "downloads": -1, "filename": "CfnCustomCFrontDistro-0.0.1.tar.gz", "has_sig": false, "md5_digest": "696a08af6f9ab617cc5c5bcb38bf7be3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 29152, "upload_time": "2019-10-30T17:52:57", "upload_time_iso_8601": "2019-10-30T17:52:57.482783Z", "url": "https://files.pythonhosted.org/packages/28/aa/28f2d1f378bd74a38ef97bbb04f6db71716d1cad87d854a68f28bd101be6/CfnCustomCFrontDistro-0.0.1.tar.gz", "yanked": false, "yanked_reason": null } ], "vulnerabilities": [] }