fbpx

How exactly to create SAML suppliers with AWS CloudFormation

As institutions grow, they often times experience an inflection stage where it becomes impractical to manually manage individual user accounts within disparate systems. Managing several AWS accounts is not any exception. Many big organizations possess dozens or a huge selection of AWS accounts spread across several business units even.

AWS provides many options that may orchestrate a individual’s identification across multiple accounts. AWS Identity and Access Administration (IAM), SAML, and OpenID might help all. The solution I explain in this article uses these functions and services and will scale to a large number of AWS accounts. It offers a repeatable and automatic opportinity for deploying a unified identification management construction across all of one’s AWS environments. It can this while extending current identity administration into AWS without having to change your present resources of user information.

About multi-account administration

This process uses AWS CloudFormation StackSets to deploy a good identity company and AWS IAM functions into multiple accounts. Roles may be tailored for the business requirements and mapped to administrators, power users, or specialized functions that perform domain-specific duties inside your environment highly. StackSets certainly are a highly scalable device for multi-accounts enforcement and orchestration of plans across an organization.

Before deploying this solution across your company, I would recommend that you deploy the stack below right into a single AWS take into account testing purposes. Then, expand the perfect solution is using StackSets across your company tested once. To find out more about AWS CloudFormation StackSets and Stacks, see our documentation.

About SAML and SAML suppliers

Security Assertion Markup Vocabulary 2.0 (SAML) can be an open regular for exchanging identification and safety information with applications along with other external systems. For instance, if your company uses Microsoft Energetic Directory, it is possible to federate your consumer accounts to other businesses through SAML assertions. Activities that users ingest the external organization may then end up being mapped to the identification of the original consumer and executed with a job which has predetermined privileges.

If you’re not used to SAML, don’t worry! It’s not only ubiquitous, it’s well documented also. Many websites utilize it to operate a vehicle their infrastructure and protection, and you may purchased it without knowing it already. To learn more about AWS and SAML, I suggest you focus on Enabling SAML for Your AWS Resources.

Correctly configured SAML federation provides core security requirements for authorization and authentication, while maintaining an individual way to obtain truth for who your users are. In addition, it enables essential constraints such as for example multi-aspect authentication and centralized gain access to administration. Within AWS IAM, you set up a SAML rely on by configuring your identification provider with information regarding AWS and the AWS IAM functions you want your federated customers to utilize. SAML is secured making use of public key authentication.

This solution is really a companion to your blog post AWS Federated Authentication with Active Directory Federation Services (AD FS), nonetheless it can be put on any SAML provider.

Solution overview

To orchestrate SAML companies across several accounts, you will require the following:

  • A basic knowledge of federated users.
  • An identity supplier that facilitates SAML, such as for example Active Directory Federation Providers (Advertisement FS), or Shibboleth.
  • An Amazon Simple Storage Service (Amazon S3) bucket to host the service provider’s federation metadata document.
  • An AWS accounts that may create StackSets in various other accounts. Usually, that is an AWS Organizations master accounts, with StackSets provisioned into associate accounts. Start to see the AWS Organizations User Guide for additional information.

Note: It is possible to adapt this treatment for retrieve federation metadata from the HTTPS endpoint, such as for example those released by hosted identification providers publicly, but this solution will not offer that.

At this time, CloudFormation will not support provisioning the SAML provider directly. However, you can make this happen with a custom resource Lambda function. The sample program code provided in this article takes that one step more and deploys your federation metadata from the protected Amazon S3 bucket, as some organizations have specifications about how exactly this metadata is kept.

Figure 1: Architecture diagramFigure 1: Architecture diagram

Right here’s what the answer architecture appears like, as shown in Shape 1:

  1. An AWS CloudFormation template is established in a AWS account. Mostly that is your master account within AWS Organizations, nonetheless it could be a standalone accounts as well.
  2. The AWS CloudFormation template is definitely deployed to some other AWS accounts inside your organization making use of AWS CloudFormation StackSets.
  3. The AWS CloudFormation StackSet generates the following resources:
    1. A brand new read-only function within AWS IAM that utilizes the brand new identity provider because the principal in the IAM part’s trust plan. It is a sample that I take advantage of to demonstrate ways to deploy IAM Roles which are bound to an individual, dedicated identity company.
    2. An execution function for a customized resource AWS Lambda perform.
    3. The AWS Lambda functionality, which creates the identification provider within the location account.
  4. The brand new AWS Lambda function can be executed, pulling your federation metadata from the learn accounts’s S3 Bucket and creating the brand new Identity Provider.

Stage 1: Upload your federation metadata to the restricted S3 bucket

To make sure that your SAML supplier’s federation metadata is exposed and then accounts inside your AWS organization, it is possible to upload the metadata to a good Amazon S3 bucket and restrict usage of accounts inside your organization. The bucket plan follows this template:



    "Version": "2012-10-17",
    "Id": "Policy1545178796950",
    "Statement": [
        
            "Effect": "Allow",
            "Principal": 
                "AWS": "*"
            ,
            "Action": "s3:GetObject",
            "Source": "arn:aws:s3:::/*",
            "Condition": 
                "StringEquals": 
                    "aws:PrincipalOrgID": ""
                
            
        
    ]

This Amazon S3 bucket policy is set up once, upload your federation metadata record to the bucket and note the thing URL.

If your company can publicly share your federation metadata, there&rsquo then;s no dependence on this bucket policy. Upload your document to the S3 bucket simply, and create the bucket accessible publicly.

Action 2: Launch the CloudFormation template

To generate the SAML service provider within AWS IAM, a custom can be used by this solution reference Lambda function, as CloudFormation will not offer the capability to create the construction directly currently. In this full case, I display you how to utilize the AWS API to produce a SAML company in all of your associate accounts, pulling the federation metadata from an S3 bucket possessed by the business master account.

The specific CloudFormation template follows. An example read-only part has been included, nevertheless, you are encouraged by me to displace this with IAM functions that make sense for the environment. Conserve this template to your neighborhood workstation, or even to your program code repository for monitoring infrastructure changes (if you want a source code administration system, we recommend AWS CodeCommit).


---
AWSTemplateFormatVersion: 2010-09-09
Description: Create SAML provider

Parameters:
  FederationName:
    Type: String
    Explanation: Name of SAML supplier being created in IAM
  FederationBucket:
    Type: String
    Explanation: Bucket containing federation metadata
  FederationFile:
    Type: String
    Description: Name of document containing the federation metadata

Resources:
  FederatedReadOnlyRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: Federated-ReadOnly
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithSAML
            Principal:
              Federated: !Sub arn:aws:iam::$AWS::AccountId:saml-provider/$FederationName
            Condition:
              StringEquals:
                SAML:aud: https://signin.aws.amazon.com/saml
      Path: '/'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/ReadOnlyAccess

  SAMLProviderCustomResourceLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: 'arn:aws:logs:*:*:log-team:/aws/lambda/*-SAMLProviderCustomResourceLambda-*:*'
              - Effect: Allow
                Action:
                  - iam:CreateSAMLProvider
                  - iam:DeleteSAMLProvider
                Source: !Sub arn:aws:iam::$AWS::AccountId:saml-provider/$FederationName
              - Effect: Allow
                Action:
                  - iam:ListSAMLProviders
                Resource: '*'
              - Effect: Allow
                Action:
                  - s3:GetObject
                Reference: !Sub 'arn:aws:s3:::$FederationBucket/*'

  CustomResource:
    Type: Custom::CustomResource
    DependsOn:
      - SAMLProviderCustomResourceLambda
      - SAMLProviderCustomResourceLambdaExecutionRole
    Properties:
      ServiceToken: !GetAtt SAMLProviderCustomResourceLambda.Arn

  SAMLProviderCustomResourceLambda:
    Type: "AWS::Lambda::Functionality"
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt SAMLProviderCustomResourceLambdaExecutionRole.Arn
      Runtime: python3.7
      Timeout: 300
      Environment:
        Variables:
          FEDERATION_NAME: !Ref FederationName
          FEDERATION_BUCKET: !Ref FederationBucket
          FEDERATION_FILE: !Ref FederationFile
      Code:
        ZipFile: |
          import boto3, json, operating system, urllib.request, ssl, period, traceback


          BUCKET = operating system.getenv('FEDERATION_BUCKET')
          FILE = operating system.getenv('FEDERATION_FILE')
          NAME = operating system.getenv('FEDERATION_NAME')


          class SAMLProvider(object):
              def __init__(self):
                  self.iam_customer = boto3.client('iam')
                  self.existing_providers = []
                  self._list_saml_companies()
                  self.s3 = boto3.source('s3')

              def get_federation_metadata(self):
                  try:
                      personal.s3.Bucket(BUCKET).download_file(FILE, '/tmp/' + Document)
                      handle = open('/tmp/' + Document)
                      data = handle.read()
                      handle.close()
                      os.remove('/tmp/' + Document)
                      return data
                  except:
                      traceback.print_exc()
                      raise

              def _list_saml_suppliers(self):
                  providers = []
                  response = self.iam_customer.list_saml_providers()
                  for provider in reaction['SAMLProviderList']:
                      self.existing_companies.append(provider['Arn'])

              def add_saml_service provider(self, name):
                  for arn in personal.existing_providers:
                      if arn.split('/')[1] == name:
                          print(name + ' currently exists as a company')
                          return False
                  response = self.iam_customer.create_saml_provider(SAMLMetadataDocument=self.obtain_federation_metadata(), Name=name)
                  print('Create reaction: ' + str(response))
                  return True

              def delete_saml_supplier(self, name):
                  for arn in personal.existing_providers:
                      if arn.split('/')[1] == name:
                          response = self.iam_customer.delete_saml_provider(SAMLProviderArn=arn)
                          print('Delete reaction: ' + str(response))

          def send_response(occasion, context, response_status, reaction_data):
              response_entire body = json.dumps(
                  'Status': response_status,
                  'Reason': 'See the facts in CloudWatch Log Stream: ' + context.log_stream_title,
                  'PhysicalResourceId': context.log_stream_name,
                  'StackId': event['StackId'],
                  'RequestId': event['RequestId'],
                  'LogicalResourceId': event['LogicalResourceId'],
                  'Data': response_data
              )
              print('ResponseURL: %s', occasion['ResponseURL'])
              print('ResponseBody: %s', reaction_body)
              try:
                  opener = urllib.request.construct_opener(urllib.request.HTTPHandler)
                  request = urllib.request.Demand(event['ResponseURL'], data=reaction_body.encode())
                  request.put_header('Content-Type', '')
                  request.increase_header('Content-Length', len(reaction_body))
                  request.get_technique = lambda: 'PUT'
                  response = opener.open up(request)
                  print("Status program code: %s", response.getcode())
                  print("Status information: %s", response.msg)
              except:
                  traceback.print_exc()


          def lambda_handler(occasion, context):
              print(event)
              print(context)
              saml = SAMLProvider()
              try:
                  if occasion['RequestType'] == 'Create':
                      saml.add_saml_service provider(NAME)
                      send_response(occasion, context, 'SUCCESS', "Message": "Resource creation successful!")
                  if occasion['RequestType'] == 'Update':
                      saml.delete_saml_company(NAME)
                      time.sleep(10)
                      saml.add_saml_supplier(NAME)
                      send_response(occasion, context, 'SUCCESS', "Message": "Resource update successful!")
                  if occasion['RequestType'] == 'Delete':
                      saml.delete_saml_service provider(NAME)
                      send_response(occasion, context, 'SUCCESS', "Message": "Resource deletion successful!")
              except:
                  send_response(occasion, context, "FAILED", "Message": "Exception during processing")
                  traceback.print_exc()

As you evaluation this template, remember that a Python Lambda functionality is embedded in the template entire body itself. It is a useful solution to package code together with your CloudFormation templates. The control for along code inline inside a CloudFormation template will be fixed, as comprehensive in the AWS CloudFormation user guide. Program code that exceeds this size should be saved to another location in a Amazon S3 bucket and referenced from your own template. Nevertheless, the preceding snippet will be short plenty of to be incorporated all in a single CloudFormation template.

Stage 3: Create the StackSet

With your SAML company metadata securely uploaded to your Amazon S3 bucket, it’s time and energy to create the StackSet.

  1. First, demand CloudFormation console and choose StackSets, Create StackSet then.

    Figure 2: Developing a brand-new StackSetFigure 2: Developing a new StackSet
  2. Select Template is ready, then Upload a template document. Select Choose document to find the located area of the CloudFormation template, select Next then.
    Shape 3: Specifying the template detailsDetermine 3: Specifying the template details

  3. Enter a worth for StackSet title. Then supply the following construction parameters and choose Next:
    1. FederationName: The title of the SAML supplier. This is the title of the service provider as you view it in IAM as soon as provisioned, and it seems in the ARN of the SAML company.
    2. FederationFile: The file title within S3.
    3. FederationBucket: The title of the S3 bucket.

     

    Shape 4: Specifying the StackSet parametersPhysique 4: Specifying the StackSet parameters
  4. In the Account numbers industry, enter the set of accounts into that you desire to provision this stack. Decide on a Area from the drop-down menus, then choose any concurrent deployment options that you’ll require. For most customers, the concurrent and failing tolerance options usually remain unmodified.

    Important: Once you enter your set of accounts, you must utilize the 12-digit accounts number for every destination, without areas, and divided by commas.

    Because IAM is really a global service, you don’t have to deploy this to several regions. The template should be deployed as soon as per AWS account, though it is managed by way of a CloudFormation Stack that is present in one Region.

    Figure 5: Choosing your deployment optionsFigure 5: Choosing your deployment options
  5. Depending on your own organization’s protection posture, you might have chosen to utilize self-managed permissions. If this is the case, you then must specify an AWS IAM part that’s permitted to execute StackSet deployments, and also an execution function in the location accounts. For more information, go to the StackSets’ Grant Self-Managed Permissions documentation web page.
  6. Review your choices, accept the IAM part creation acknowledgment, and click on Submit to generate your stacks. Completed once, ensure that the brand new identity provider exists in each account at the AWS IAM console.

Summary

Developing a SAML provider throughout multiple AWS accounts allows enterprises to increase their present authentication infrastructure in to the cloud.

You can extend the perfect solution is provided here to deploy different federation metadata to AWS accounts predicated on specific requirements—for example, if your advancement and staging accounts have another identity provider. You may also add easy logic to the Lambda functionality that I’ve contained in the CloudFormation template. Additionally, you may want to create a variety of predefined roles inside your AWS organization—using the StackSets process enables a zero-touch opportinity for creating these functions from the central location.

Organizations searching for even stronger settings over a number of accounts should put into action this solution with AWS Organizations. Coupled with federated entry and centrally handled IAM roles, Organizations provides Service Handle Policies and a standard framework for deploying CloudFormation Stacks across several business units.

In case you have feedback concerning this post, submit feedback in the Comments section below. For those who have questions concerning this post, contact AWS Support.

Want a lot more AWS Security how-to content material, news, and show announcements? Adhere to us on Twitter.

Writer

Wealthy McDonough

Rich McDonough is really a Options Architect for Amazon Internet Services located in Toronto. His main focus is on Administration and Governance, helping customers level their usage of AWS safely and safely. Before joining AWS 2 yrs back, he specialized in assisting migrate customers in to the cloud. Rich enjoys helping customers find out about AWS CloudFormation, AWS Config, and AWS Handle Tower.

%d bloggers like this: