<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniel Kim</title>
    <description>The latest articles on Forem by Daniel Kim (@namuny).</description>
    <link>https://forem.com/namuny</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F358979%2Fc7c2b23c-35ec-469a-86b4-12ac6effb83c.jpg</url>
      <title>Forem: Daniel Kim</title>
      <link>https://forem.com/namuny</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/namuny"/>
    <language>en</language>
    <item>
      <title>Using cfn-lint to validate your CloudFormation template</title>
      <dc:creator>Daniel Kim</dc:creator>
      <pubDate>Sat, 30 May 2020 11:22:05 +0000</pubDate>
      <link>https://forem.com/namuny/using-cfn-lint-to-validate-your-cloudformation-template-jpa</link>
      <guid>https://forem.com/namuny/using-cfn-lint-to-validate-your-cloudformation-template-jpa</guid>
      <description>&lt;p&gt;If you've used CloudFormation before you'll already know about the &lt;code&gt;validate-template&lt;/code&gt; command on AWS CLI. If you've used this command before, you might also know that this validator &lt;em&gt;only&lt;/em&gt; checks the syntax of your template. I can think of countless cases where my deployments failed due to a simple mistake that wasn't caught by this validator. This post will use a simple CloudFormation template to explain how &lt;code&gt;cfn-lint&lt;/code&gt; can help you identify various errors in your stack before deploying it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sections
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Example Template Setup&lt;/li&gt;
&lt;li&gt;cfn-lint Usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Example Template Setup &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: "2010-09-09"
Description: Example template
Parameters:
  Environment:
    Type: String
    Default: 'dev'
Conditions:
  IsDev: !Equals [ !Ref Environment, 'dev' ]
Resources:
  Function:
    Type: AWS::Lambda::Function
    Condition: IsDev
    Properties:
      Role: !Ref FunctionRole # Role property requires an ARN, not the resource ID
      Handler: index.handler
      Code:
        S3Bucket: my-bucket
        S3Key: function.zip
      MemorySize: 3000 # Invalid memory size
      Runtime: nodejs12.x
      Timeout: 5
      TracingConfig:
        Mode: !If [IsTracingActive, 'true', 'false'] # Undefined condition IsTracingActive
  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: all
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: '*'
                Resource: '*'
Outputs:
  FunctionArn: # Export without matching condition to resource
    Description: Lambda ARN
    Value: !GetAtt Function.Arn
    Export:
      Name: !Sub ${Environment}-lambda-arn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is the template that we'll use to test &lt;code&gt;cfn-lint&lt;/code&gt;. It sets up a simple Lambda function with an IAM role and the lambda ARN is exported as an output. Before we start, let's highlight some of the issues with this template:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Role&lt;/code&gt; property on the lambda is not an ARN. Running a &lt;code&gt;Ref&lt;/code&gt; on an IAM role will return the logical ID of the role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;MemorySize&lt;/code&gt; of 3000 is invalid. Lambda memory size can range from 128 MB to 3008 MB in 64 MB increments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Condition &lt;code&gt;IsTracingActive&lt;/code&gt; is undefined.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;LambdaFunction&lt;/code&gt; is only deployed when the condition &lt;code&gt;IsDev&lt;/code&gt; is true, but it's export does not have the condition defined.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the output of the built-in &lt;code&gt;validate-template&lt;/code&gt; command for this stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]", 
    "Description": "Example template", 
    "Parameters": [
        {
            "DefaultValue": "dev", 
            "NoEcho": false, 
            "ParameterKey": "Environment"
        }
    ], 
    "Capabilities": [
        "CAPABILITY_IAM"
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, the validator does not identify any issues with this stack. Deploying this stack however will result in a failure. Let's see what &lt;code&gt;cfn-lint&lt;/code&gt; can do for us in the next section.&lt;/p&gt;

&lt;h1&gt;
  
  
  cfn-lint Usage &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;cfn-lint&lt;/code&gt; is a command line tool which examines your CloudFormation template and returns various suggestions. Let's run this tool and see what it has to say about our example stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; cfn-lint template.yml

E3008 Property "Role" has no valid Refs to Resources at Resources/Function/Properties/Role/Ref
template.yml:14:7

E2530 You must specify a value that is greater than or equal to 128, and it must be a multiple of 64. You cannot specify a size larger than 3008. Error at Resources/Function/Properties/MemorySize
template.yml:19:7

E8002 Condition IsTracingActive is not defined.
template.yml:23:9

W1001 GetAtt to resource "Function" that may not be available when condition "IsDev" is False at Outputs/FunctionArn/Value/Fn::GetAtt
template.yml:47:5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, &lt;code&gt;cfn-lint&lt;/code&gt; output covers all 4 issues that we previously highlighted in the form of warnings and errors. Errors indicate issues that will prevent your CloudFormation stack from deploying, and warnings indicate potential issues in your stack that you might want to think about.&lt;/p&gt;

&lt;p&gt;It's worth noting that not all warnings are necessarily highlighting an issue that you &lt;em&gt;must&lt;/em&gt; fix. Everything depends on the context. If you wish to ignore warnings from the output, you can use the ignore_checks argument:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; cfn-lint template.yml -i W
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cfn-lint&lt;/code&gt; also comes with extensive configuration support which allows you to customise your linting rules.&lt;/p&gt;

&lt;p&gt;For a complete set of commands and installation guides, please refer to the &lt;a href="https://github.com/aws-cloudformation/cfn-python-lint"&gt;github repository&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We looked at how &lt;code&gt;cfn-lint&lt;/code&gt; can be used as an additional validator for our CloudFormation templates. It provides a way to check the semantics of our templates and helps us catch mistakes before making a deployment. Some of the CI pipelines that I work on uses &lt;code&gt;cfn-lint&lt;/code&gt; to decide whether the deployment step should execute. I hope this tool can help you iterate quicker and make your CloudFormation development experience a bit more enjoyable.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudformation</category>
    </item>
    <item>
      <title>How to secure your S3 bucket from users with s3:* access</title>
      <dc:creator>Daniel Kim</dc:creator>
      <pubDate>Fri, 24 Apr 2020 11:14:28 +0000</pubDate>
      <link>https://forem.com/namuny/how-to-secure-your-s3-bucket-from-users-with-s3-access-5503</link>
      <guid>https://forem.com/namuny/how-to-secure-your-s3-bucket-from-users-with-s3-access-5503</guid>
      <description>&lt;p&gt;I recently worked on adding an extra layer of access control for some of the S3 buckets at work. This required me to allow only a specific group of employees to have direct access to the buckets. The problem is that a lot of them can assume an IAM role which gives them &lt;code&gt;s3:*&lt;/code&gt; capabilities. In this post I will use an example of two users and IAM roles with read access to all buckets to show how we can restrict access for one user.&lt;/p&gt;

&lt;h1&gt;
  
  
  Who is this post for?
&lt;/h1&gt;

&lt;p&gt;This post is for you if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to restrict access to certain S3 buckets &lt;strong&gt;even if users have read access to all buckets through their IAM role&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Sections
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;Bucket Policy&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Setup &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;In this section we'll set up some mock data which will help us test our bucket policy. This includes creating new users, policies, groups, and roles. You may skip this section and move on to Bucket Policy if you already have this data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F58h3yevdexfyob8ppesh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F58h3yevdexfyob8ppesh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Let's start off by creating an S3 bucket. I used the default settings since we don't need the bucket to be public for this example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsyeghbvlh06ltzqosedg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsyeghbvlh06ltzqosedg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to IAM and create two roles with &lt;em&gt;AmazonS3ReadOnlyAccess&lt;/em&gt; policy. This policy will give the roles read only access to &lt;strong&gt;all&lt;/strong&gt; buckets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvrdayhpunulg7fd9cvs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvrdayhpunulg7fd9cvs2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
We will now create policies to allow our users to assume these roles. Go to &lt;em&gt;Policies&lt;/em&gt; menu and create two policies. For both policies, select &lt;em&gt;STS&lt;/em&gt; as the service and &lt;em&gt;AssumeRole&lt;/em&gt; as the action. For resources, click on &lt;em&gt;Add ARN&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjhi34jcbtqxdo0alsvlc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjhi34jcbtqxdo0alsvlc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Type in each of the two role names for each policy as well as your AWS account ID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1atdfehjcoxj70xoaaax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1atdfehjcoxj70xoaaax.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;Groups&lt;/em&gt; to create two groups. Attach one of the policies to each of these groups.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8w3hrmoctsrg8kme1xxb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8w3hrmoctsrg8kme1xxb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Lastly, navigate to &lt;em&gt;Users&lt;/em&gt;. As you may have guessed, we'll be creating two users. Make sure that &lt;em&gt;AWS Management Console access&lt;/em&gt; is ticked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftfgfr80sgqqrkn3nb1dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftfgfr80sgqqrkn3nb1dw.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Add each of the users to separate groups that you previously created.&lt;/p&gt;

&lt;p&gt;If you've been following the post, you'll now have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two roles with &lt;em&gt;AmazonS3ReadOnlyAccess&lt;/em&gt; policy&lt;/li&gt;
&lt;li&gt;Two policies with &lt;em&gt;sts:AssumeRole&lt;/em&gt; access to &lt;strong&gt;one&lt;/strong&gt; of the two roles&lt;/li&gt;
&lt;li&gt;Two groups with &lt;strong&gt;one&lt;/strong&gt; of the two policies above&lt;/li&gt;
&lt;li&gt;Two users in &lt;strong&gt;one&lt;/strong&gt; of the two groups above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We now have all the data to write our S3 bucket policy.&lt;/p&gt;
&lt;h1&gt;
  
  
  Bucket Policy &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;In this section, we'll add a bucket policy which allows specific IAM roles to have read access.&lt;/p&gt;

&lt;p&gt;Before we start with the bucket policy, we need to know the ID of the IAM role that &lt;strong&gt;should&lt;/strong&gt; have access to our S3 bucket. We'll use &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; to achieve this. If you don't have this set up, I recommend reading &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html" rel="noopener noreferrer"&gt;this&lt;/a&gt; article from AWS.&lt;/p&gt;

&lt;p&gt;Once you have AWS CLI set up, run the following command on your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; aws iam get-role --role-name YOUR_ROLE_NAME
{
    "Role": {
        "AssumeRolePolicyDocument": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": "sts:AssumeRole", 
                    "Effect": "Allow", 
                    "Condition": {}, 
                    "Principal": {
                        "AWS": "arn:aws:iam::12345678:root"
                    }
                }
            ]
        }, 
        "MaxSessionDuration": 3600, 
        "RoleId": "AROACHA7SAS77861CKA", 
        "CreateDate": "2020-04-24T08:23:30Z", 
        "RoleName": "access", 
        "Path": "/", 
        "Arn": "arn:aws:iam::12345678:role/access"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take note of the &lt;code&gt;RoleId&lt;/code&gt;. We will need to use this information in our bucket policy.&lt;/p&gt;

&lt;p&gt;Bucket policy is a JSON based IAM policy which can define entities that can/cannot access the content of your bucket. The bucket policy that we will add today looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::${BUCKET_NAME}",
                "arn:aws:s3:::${BUCKET_NAME}/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": "${ROLE_ID}:*"
                }
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This policy denies all requests on the bucket if the requester is not using a specific IAM role. You'll need to manually fill out the &lt;code&gt;BUCKET_NAME&lt;/code&gt; and &lt;code&gt;ROLE_ID&lt;/code&gt;. The &lt;code&gt;:*&lt;/code&gt; on the condition allows us to filter for any sessions that assume this role. This is because the &lt;code&gt;userId&lt;/code&gt;includes random session identifiers when assuming a role.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fobofuuzj8qotv6ji80oc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fobofuuzj8qotv6ji80oc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head over to your S3 bucket and navigate to &lt;em&gt;Bucket Policy&lt;/em&gt; under &lt;em&gt;Permissions&lt;/em&gt;. Add your bucket policy and click &lt;em&gt;Save&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you've come this far, your bucket should now be accessible by only the IAM role that you've specified. Next section will show an example of how you can test this.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fux5qwbzi32syg868ourg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fux5qwbzi32syg868ourg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Head over to the &lt;a href="https://console.aws.amazon.com/console/home" rel="noopener noreferrer"&gt;AWS Management Console Login page&lt;/a&gt;. Select &lt;em&gt;IAM user&lt;/em&gt; and enter your account number. Enter the credentials for the user that can assume the IAM role which &lt;em&gt;should not&lt;/em&gt; have access to your bucket.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgi2spklo0neuxprev8gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgi2spklo0neuxprev8gb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Open the menu on the top right corner and click &lt;em&gt;Switch Role&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv2ndlwjodxd0qz058wei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv2ndlwjodxd0qz058wei.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Enter your account number again, and the name (not the ARN) of the IAM role that this user should be able to assume. Click &lt;code&gt;Switch Role&lt;/code&gt;. Once you've successfully assumed the role, you'll see an indicator on the top right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdccaoibsskk56f1pa0ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdccaoibsskk56f1pa0ip.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to S3 and confirm that the user does not have access to your S3 bucket. This can be seen from the &lt;code&gt;Error&lt;/code&gt; message under &lt;code&gt;Region&lt;/code&gt;. You can also click on the bucket to confirm that the user cannot see the content of the bucket. Repeat this process for the user that &lt;em&gt;should&lt;/em&gt; have access to your bucket.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We've looked at how we can use bucket policies to prevent people from accessing your S3 bucket even if they have access to read from all S3 buckets. We use an explicit deny policy which is scalable, since we don't need to update the policy as new IAM roles are added to the AWS account.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>iam</category>
    </item>
    <item>
      <title>Using Cognito User Pool as an OpenID Connect Provider</title>
      <dc:creator>Daniel Kim</dc:creator>
      <pubDate>Tue, 14 Apr 2020 10:56:49 +0000</pubDate>
      <link>https://forem.com/namuny/using-cognito-user-pool-as-an-openid-connect-provider-4n9a</link>
      <guid>https://forem.com/namuny/using-cognito-user-pool-as-an-openid-connect-provider-4n9a</guid>
      <description>&lt;p&gt;Couple of weeks ago I was involved in a hackathon which involved integrating two Cognito user pools together. During my investigation I discovered that Cognito user pool supports OAuth2 for user authentication. This post will outline how you can use Cognito user pool as an OIDC provider as well as how you can connect two user pools together.&lt;/p&gt;

&lt;h1&gt;
  
  
  Who is this post for?
&lt;/h1&gt;

&lt;p&gt;This post is for you if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have basic understanding of AWS Cognito user pools&lt;/li&gt;
&lt;li&gt;Want to know how Cognito user pools can be used as a OIDC provider&lt;/li&gt;
&lt;li&gt;How to associate two user pools together through federated identity providers&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Sections
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;What is OpenID Connect?&lt;/li&gt;
&lt;li&gt;User Pool Setup&lt;/li&gt;
&lt;li&gt;Configuring Federated Identity Provider&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What is OpenID Connect? &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;OpenID is a protocol which provides a mechanism to authenticate users through a third party. This means that users can login to your application with existing accounts on other platforms. When a user completes the OIDC flow, your application can gain access to some of their information from the third party in the form of an &lt;code&gt;id_token&lt;/code&gt; which is a JWT token.&lt;/p&gt;

&lt;h1&gt;
  
  
  User Pool Setup &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;In this section we'll create two Cognito user pools and configure them so they can integrate together. &lt;code&gt;oidc-pool-1&lt;/code&gt; will be the master user pool which uses &lt;code&gt;oidc-pool-2&lt;/code&gt; as a federated identity provider. We'll create a user in &lt;code&gt;oidc-pool-2&lt;/code&gt; and keep &lt;code&gt;oidc-pool-1&lt;/code&gt; empty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw85z4lq7prb7emt9h19c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw85z4lq7prb7emt9h19c.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search for &lt;em&gt;Cognito&lt;/em&gt; on the AWS console and click on &lt;em&gt;Manage User Pools&lt;/em&gt;. Click &lt;em&gt;Create a user pool&lt;/em&gt; on the top right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fer9f003c7ccppotybzqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fer9f003c7ccppotybzqx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After entering the name of your user pool, you are presented with two options. I'll be clicking &lt;em&gt;Review defaults&lt;/em&gt; for the purpose of this demo but you're welcome to step through the settings. This option will let you specify some crucial settings for your user pool such as required attributes for a user. Note that this information &lt;strong&gt;cannot&lt;/strong&gt; be changed once you create your user pool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fydkqncz9hm3uporlgb54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fydkqncz9hm3uporlgb54.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Once you've created a user pool, navigate to &lt;em&gt;App clients&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxapwoist3au23oo48389.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxapwoist3au23oo48389.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
An app client has access to invoke certain endpoints on your user pool while being unauthenticated. Decide on a name and create the app client. We'll leave rest of the settings as is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F759oj6dqfgv3w1s4tw0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F759oj6dqfgv3w1s4tw0f.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Head over to the &lt;em&gt;Domain name&lt;/em&gt; page and register a domain for your user pool. Take note of the domain that you enter here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt6j2eeufictvrh4fztb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt6j2eeufictvrh4fztb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Repeat the process above and create another user pool. Apply the exact same configuration as the first user pool. Take note of the &lt;em&gt;App client id&lt;/em&gt; and &lt;em&gt;App client secret&lt;/em&gt; as well as the &lt;em&gt;Pool Id&lt;/em&gt; for the second user pool, we will need this when we integrate the two user pools together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt6j2eeufictvrh4fztb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvt6j2eeufictvrh4fztb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you followed the post up to this point, you'll now have two Cognito user pools, each with an app client and a domain. If you're satisfied with your setup, navigate to &lt;em&gt;App client settings&lt;/em&gt; of your &lt;strong&gt;second&lt;/strong&gt; user pool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj7vnydmzcxfs5uma3tif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj7vnydmzcxfs5uma3tif.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
This is where the integration begins. Choose &lt;em&gt;Select all&lt;/em&gt; for &lt;em&gt;Enabled Identity Providers&lt;/em&gt; and set the &lt;em&gt;Callback URL(s)&lt;/em&gt; in the following format:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

https://${USER_POOL_DOMAIN}/oauth2/idpresponse


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This allows users authenticated with the second user pool to be redirected to the master user pool. &lt;/p&gt;

&lt;p&gt;Since I didn't prepare any web app to demo this integration, I'm setting a random value on the &lt;em&gt;Sign out URL(s)&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6n6448tyojog4yx71le8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6n6448tyojog4yx71le8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Select &lt;em&gt;Authorization code grant&lt;/em&gt; and &lt;em&gt;openid&lt;/em&gt; under &lt;em&gt;OAuth 2.0&lt;/em&gt; and click &lt;em&gt;Save changes&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring Federated Identity Provider &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Cognito user pools support integration with federated identity providers such as Google and Facebook. We'll use this feature to integrate our user pools together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffg3g8astt3xtczuiis7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffg3g8astt3xtczuiis7o.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;Identity providers&lt;/em&gt; on the &lt;strong&gt;first&lt;/strong&gt; user pool. Select &lt;em&gt;OpenID Connect&lt;/em&gt; and you'll see the form below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8zdmuugigoaz2io8qoq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8zdmuugigoaz2io8qoq9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how you should fill in the form:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Provider name: Arbitrary name
Client ID: App client id of the second user pool
Client secret: App client secret of the second user pool
Attributes request method: GET
Authorize scope: openid
Issuer: https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;User pool ID can be found on the &lt;em&gt;General settings&lt;/em&gt; menu. Click on &lt;em&gt;Run discovery&lt;/em&gt; once you've filled in the form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Febsh070nhacgvoijelbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Febsh070nhacgvoijelbv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Don't be worried if you see this warning.&lt;/p&gt;

&lt;p&gt;Open a new tab in your browser and navigate to &lt;a href="https://cognito-idp.$%7BREGION%7D.amazonaws.com/$%7BSECOND_USER_POOL_ID%7D/.well-known/openid-configuration" rel="noopener noreferrer"&gt;https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}/.well-known/openid-configuration&lt;/a&gt;. You'll see a JSON response with a set of properties. This information can be used to fill in the rest of the form.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Authorization endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/authorize
Token endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/token
Userinfo endpoint: https://${SECOND_USER_POOL_DOMAIN}/oauth2/userInfo
Jwks uri: https://cognito-idp.${REGION}.amazonaws.com/${SECOND_USER_POOL_ID}/.well-known/jwks.json


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Click on &lt;em&gt;Create provider&lt;/em&gt; Once you've filled in the form completely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvo5xqqqskdkyzjxqyl4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvo5xqqqskdkyzjxqyl4t.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;App client settings&lt;/em&gt; on your &lt;strong&gt;master&lt;/strong&gt; user pool. Select the name of the federated identity provider that you just added (and &lt;em&gt;Cognito User Pool&lt;/em&gt; if you want to support direct login through this client). Add suitable URLs for callback and sign out. Check &lt;em&gt;Authorization code grant&lt;/em&gt; and &lt;em&gt;openid&lt;/em&gt; in OAuth 2.0 and click on &lt;em&gt;Save changes&lt;/em&gt;. There is only one step left to integrate the two user pools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fna658kn0d1l2tni7kfcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fna658kn0d1l2tni7kfcg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;Attribute mapping&lt;/em&gt; page of the &lt;strong&gt;master&lt;/strong&gt; user pool. Click on the &lt;em&gt;OIDC&lt;/em&gt; tab. This form indicates how the attributes of the &lt;strong&gt;second&lt;/strong&gt; user pool maps to the attributes of the &lt;strong&gt;master&lt;/strong&gt; user pool. &lt;/p&gt;

&lt;p&gt;When you land on this page for the first time, you'll only see a &lt;code&gt;sub&lt;/code&gt; attribute. This is a built-in mapping which acts as a unique identifier of the user. If you're using the default user pool configurations you can add the email related mappings as can be seen above. Otherwise you'll want to map whatever attribute makes sense for your use case. Note that you &lt;strong&gt;must&lt;/strong&gt; add attributes that are marked as &lt;em&gt;required&lt;/em&gt; on your &lt;strong&gt;master&lt;/strong&gt; user pool. Click on &lt;em&gt;Save changes&lt;/em&gt; once you're happy with the attribute mapping.&lt;/p&gt;

&lt;p&gt;This marks the end of this integration! Continue to the next section if you want to find out how you can test it using Cognito Hosted UI.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;To simply the testing process, we'll be using Cognito Hosted UI. This is a built-in set of UI elements that allows users to perform basic auth flows such as sign-in, sign-up and sign-out. In reality, you might be using a custom web app with a library such as &lt;a href="https://aws.amazon.com/amplify/" rel="noopener noreferrer"&gt;AWS Amplify&lt;/a&gt; to simplify the authentication process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4xwzpah5vgbo6onb9h00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4xwzpah5vgbo6onb9h00.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;Users and groups&lt;/em&gt; on the &lt;strong&gt;second&lt;/strong&gt; user pool and create a user. For the sake of this post I'll have &lt;em&gt;Mark email as verified&lt;/em&gt; ticked. If you're using the same user pool configuration as I am, your user will be in &lt;em&gt;FORCE_CHANGE_PASSWORD&lt;/em&gt; state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2a4u23zuekvvsh07xbnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2a4u23zuekvvsh07xbnt.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to &lt;em&gt;App client settings&lt;/em&gt; on your &lt;strong&gt;master&lt;/strong&gt; user pool and click on &lt;em&gt;Launch Hosted UI&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F745fgx1u6i2m0dqpeiim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F745fgx1u6i2m0dqpeiim.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you selected both &lt;em&gt;YOUR_OIDC_PROVIDER_NAME&lt;/em&gt; and &lt;em&gt;Cognito User Pool on your *App client settings&lt;/em&gt;, you'll see the same page as I do. Click on the button below &lt;em&gt;Sign in with your corporate ID&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F43djvtxc615r5dbapyj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F43djvtxc615r5dbapyj8.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
From this page you can sign in as the user you've created on your &lt;strong&gt;second&lt;/strong&gt; user pool. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqfgvxfhk8zsd8l9nj0hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqfgvxfhk8zsd8l9nj0hg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Depending on your user pool configurations, you might see this page when you sign in. Simply enter a new password for your user. After this step you may notice that your user in the &lt;strong&gt;second&lt;/strong&gt; user pool is now in a &lt;em&gt;CONFIRMED&lt;/em&gt; state. Try logging in again on the Hosted UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fks7hkkbln4dxu14nlbfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fks7hkkbln4dxu14nlbfy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you're redirected to google.com (or whatever your redirect URL on the &lt;strong&gt;master&lt;/strong&gt; user pool is) with the &lt;code&gt;code&lt;/code&gt; in the query parameter, you've set everything up correctly and the integration is working as expected! Head over to &lt;em&gt;Users and groups&lt;/em&gt; on your &lt;strong&gt;master&lt;/strong&gt; user pool to confirm that a new user has been created (it was previously empty). This user should have correct attributes pulled from the &lt;strong&gt;second&lt;/strong&gt; user pool.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We've seen how Cognito user pool can be used as an OIDC provider as well as how we can use this concept to associate two user pools together. If you want to integrate your user pool with another service, you can use the same endpoints provided on this post.&lt;/p&gt;

&lt;p&gt;Lastly if you want to integrate this flow with a web app, I again recommend looking into &lt;a href="https://aws-amplify.github.io/docs/js/authentication" rel="noopener noreferrer"&gt;AWS Amplify and how it handles authentication&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cognito</category>
      <category>oidc</category>
      <category>openid</category>
    </item>
    <item>
      <title>Integrating AWS CloudFront with Third Party Domain Provider</title>
      <dc:creator>Daniel Kim</dc:creator>
      <pubDate>Tue, 07 Apr 2020 12:05:44 +0000</pubDate>
      <link>https://forem.com/namuny/integrating-aws-cloudfront-with-third-party-domain-provider-2ce3</link>
      <guid>https://forem.com/namuny/integrating-aws-cloudfront-with-third-party-domain-provider-2ce3</guid>
      <description>&lt;p&gt;I recently had to host a website with CloudFront, S3 and a domain from NameCheap. To my surprise, this process was not as simple as I initially thought. There was a lot of conflicting information spread across the web and I had to do some digging in order to get it just right. I'd like to share the exact steps that I followed to integrate CloudFront with a third party domain provider.&lt;/p&gt;

&lt;h1&gt;
  
  
  Who is this post for?
&lt;/h1&gt;

&lt;p&gt;This post is for you if you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a website hosted on S3 through static web hosting&lt;/li&gt;
&lt;li&gt;Have a domain from a non-AWS domain provider such as NameCheap&lt;/li&gt;
&lt;li&gt;Want to set up bare domain (non-www) for your website&lt;/li&gt;
&lt;li&gt;Want to set up HTTPS redirect on your website&lt;/li&gt;
&lt;li&gt;Want to keep your S3 bucket private&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Sections
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Request Certificate from AWS Certificate Manager&lt;/li&gt;
&lt;li&gt;Block public access on S3&lt;/li&gt;
&lt;li&gt;Create CloudFront Distribution&lt;/li&gt;
&lt;li&gt;Link CloudFront distribution with DNS Provider&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Request Certificate from AWS Certificate Manager &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;A website needs an &lt;strong&gt;SSL certificate&lt;/strong&gt; in order to use HTTPS. The certificate is issued by a Certificate Authority. AWS Certificate Manager (ACM) is a service which, in their own words, &lt;em&gt;handles the complexity of creating and managing public SSL/TLS certificates for your AWS based websites and applications&lt;/em&gt;. We will use ACM to generate a certificate that we can later use in our CloudFront distribution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F12618c1uhjhvaxjei9ac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F12618c1uhjhvaxjei9ac.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
If you don't have any certificates, this is the screen that you'll see when you navigate to ACM. Before you go any further, please note that you &lt;strong&gt;must&lt;/strong&gt; be in the us-west-1 region. CloudFront only supports ACM certificates from this region. This does not mean that your CloudFront distribution has to be in us-west-1. Click &lt;em&gt;Get Started&lt;/em&gt; under &lt;em&gt;Provision Certificates&lt;/em&gt; to continue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F053lfst4doz4gilsimgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F053lfst4doz4gilsimgh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Select &lt;em&gt;Request a public certificate&lt;/em&gt; and click &lt;em&gt;Request a certificate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F439ezungod9m3wcjdurc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F439ezungod9m3wcjdurc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add your domain names. If you want to set up a bare domain, click on &lt;em&gt;Add another name to this certificate&lt;/em&gt; and enter the it on the new text field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fweql8bpe0s5qoxa1ynff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fweql8bpe0s5qoxa1ynff.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
This is how it would look if I wanted to add &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt; and the bare domain example.com.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbmdovic6usdp7gh8tfgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbmdovic6usdp7gh8tfgx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Select a validation method. Since this post assumes that you have full control of your DNS configuration, we'll select &lt;em&gt;DNS validation&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Add relevant tags and confirm the request once you've reviewed it.&lt;/p&gt;

&lt;p&gt;If you followed the post up to this point, you'll see a screen like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F30s1vyd2rfvfu78kf8rd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F30s1vyd2rfvfu78kf8rd.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ACM provides a Name/Value pair for each domain that you've added. As you may have noticed, they follow a certain format.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Name=_RANDOM_STRING_0.DOMAIN_NAME.
Value=_RANDOM_STRING_1.RANDOM_STRING_2.acm-validations.aws.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;All of the domains are in &lt;em&gt;Pending validation&lt;/em&gt; status. In order to prove that you own these domain names, you'll need to add these as a CNAME record. Head over to the DNS configuration page of your domain provider. This is called &lt;em&gt;Advanced DNS&lt;/em&gt; on Namecheap.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4j08rl8kn21th2nxvps6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4j08rl8kn21th2nxvps6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The exact Name/Value that you need to enter on this page varies between each domain provider. During my investigation, I noticed two main variations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Some DNS providers don't allow a leading underscore.&lt;/li&gt;
&lt;li&gt;Some DNS providers append host name to the key automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the sake of this post, let's say that you have the following Name/Value pair from ACM:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Name=_1234567890.www.example.com.
Value=_0987654321.abcdefg.acm-validations.aws.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should format your CNAME record in the following way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If leading underscore is not allowed, simply remove it&lt;/li&gt;
&lt;li&gt;If host name is automatically populated, remove &lt;code&gt;.hostname.com.&lt;/code&gt; from the Name. 
Following these rules, the resulting Name could look like:
```
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Name=_1234567890.www&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/idwqu703wux31p792po6.png)
While we're at it, we'll also add a URL Redirect record to support bare domains. Note that the *@* symbol indicates the current domain.


Once you add the CNAME records, you need to wait until ACM validates them. However, you probably want to make sure that you've set them up correctly. You can achieve this with dig.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;dig cname FULL_NAME_FROM_ACM&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
If you've done everything correctly, you'll see the correct Value from ACM on the ANSWER SECTION of the response. Note that it can take a couple of minutes for your records to propagate.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/luw1qci8yg0m41dda13h.png)
When ACM successfully validates your domain name, your certificate will be in *Issued* status.


# Block public access on S3 &amp;lt;a name="chapter-2"&amp;gt;&amp;lt;/a&amp;gt;
This post assumes that you already have a website hosted on S3 through static web hosting. We'll go over how to make sure that only CloudFront can access your bucket. If you don't need to block public access to the bucket, you can skip this section.


In order to deny anyone other than CloudFront from accessing your bucket, we'll set up an explicit deny on the bucket policy. This will include a random referer header:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;{&lt;br&gt;
    "Version": "2012-10-17",&lt;br&gt;
    "Statement": [&lt;br&gt;
        {&lt;br&gt;
            "Sid": "PublicReadGetObject",&lt;br&gt;
            "Effect": "Deny",&lt;br&gt;
            "Principal": "&lt;em&gt;",&lt;br&gt;
            "Action": "s3:GetObject",&lt;br&gt;
            "Resource": "arn:aws:s3:::your-bucket-name/&lt;/em&gt;",&lt;br&gt;
            "Condition": {&lt;br&gt;
                "StringNotEquals": {&lt;br&gt;
                    "aws:Referer": "1234567898767543321123"&lt;br&gt;
                }&lt;br&gt;
            }&lt;br&gt;
        }&lt;br&gt;
    ]&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Generate a random string for your header value and save the bucket policy. Take note of this value, you'll need it when you create your CloudFront distribution



# Create CloudFront Distribution &amp;lt;a name="chapter-3"&amp;gt;&amp;lt;/a&amp;gt;
Navigate to CloudFront page on the AWS console and click on *Create Distribution*. Since we want to host a website, you'll want to create a Web distribution.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4wviq6ma79qp1sidhgrz.png)

Most of the fields on this form should be filled out according to your needs, so I'll focus on the key fields for this integration.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/imwfbldh0pufuzt2q8nu.png)

This is where you add your referer header. The value should match the random string in your bucket policy. Note that *aws:* is omitted from the header name.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6vh58jn4aer73h40lyxn.png)

Select the certificate that you requested. Note that your certificate has to be in the *Issued* status for this to work.

Fill in the rest of the form and create the distribution.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dlhejwp0v18ipooel0pc.png)

You'll need to wait until your distribution is in the *Deployed* state. This may take some time. Take note of your distribution's domain name, you'll need this soon.

# Link CloudFront distribution with DNS Provider &amp;lt;a name="chapter-4"&amp;gt;&amp;lt;/a&amp;gt;
This is the last step of the integration. If you've come this far on your first attempt, you're doing much better than I did.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qei1prd0i7vlzhp6wz5d.png)

Open your DNS configuration page again and add a new CNAME record. This allows your domain name to point to your CloudFront distribution. Note how I'm using *www* as the host. This is because Namecheap automatically appends the host name. If your DNS provider doesn't support this, you'll want to add the entire domain name.

As you've seen before, it can take some time for this record to propagate. You can use the dig tool to validate your configuration.


# Conclusion
And that's it! Your CloudFront + S3 + third party domain provider integration should now work while keeping your S3 bucket from being accessed by anyone else. For something that sounds so simple conceptually, it took me an embarrassing amount of time to get this right. Many of the configurations in this integration can take a long time to propagate, so trial and error can become a real hassle. I hope this post can help people save some time.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>cloudfront</category>
      <category>s3</category>
      <category>aws</category>
      <category>dns</category>
    </item>
  </channel>
</rss>
