3

While setting up my Organization in AWS I stumbled upon a problem. We plan to use AWS Organizations to separate different departments (Dev, Operations, IT, Projects) into different AWS Accounts and AWS SSO to Manage Cross-account access. In some departments (Dev, Projects)

I want some users to be able to create own IAM Users (Called "Function Users") for use for programmatic access. These Function Users should have no right to create users themselves nor set update any access keys. Additionally these Users (or their Access keys) should be valid only for a limited time. The idea is that if a employee leaves the company the created function user stays valid only for a limited time (If not found while deactivating the employee user).

I plan to implement the time limit by calling a lambda-Function once a day to deactivate access keys of all function users that are older than a given time.

My problem is setting the Limit on the rights of the created users. I created a SSO Permissions set (Which is mapped to a Role in each account) that has the AWS managed policy "IAMReadOnlyAccess" attached. Additionally it has the following inline policy:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "CreateUsersWithTag",
        "Effect": "Allow",
        "Action": [
            "iam:CreateUser",
            "iam:DeleteUserPolicy",
            "iam:AttachUserPolicy",
            "iam:DetachUserPolicy",
            "iam:PutUserPermissionsBoundary"
        ],
        "Resource": "*",
        "Condition": {
            "StringEquals": {
                "aws:RequestTag/Owner": "${aws:username}",
                "iam:PermissionsBoundary": "arn:aws:iam::12356789012:policy/FunctionUserBoundary"
            }
        }
    }
]
}

With this Policy I try to force all created users to have a Tag with the creating user (to identify function users and allow that user to update access keys). I also try to force a IAM Policy to that newly created user which denys any IAM access for the function user.

My Problem is the ARN of that policy. It resides in the master Account of the organization. Therefor a user can not reference it in a sub-account when creating a user.

Is there a way to allow sub-accounts access to IAM Policys of another account? Another Option would be to write a Lambda function that is triggered on account creation that creates the FunctionUserBoundary policy in each new account and change the iam:PermissionsBoundary value to arn:aws:iam::*:policy/FunctionUserBoundary but when I change the policy later I will end up with different policy Versions in different accounts.

Is there a way to implement my plan or is my plan fundamentally wrong?

Clemens Bergmann
  • 305
  • 1
  • 4
  • 13

2 Answers2

2

I used a variant of the Answer by MLu:

I created a CloudFormation StackSet that roles out all the policys and a custom lambda function that is called each time a new account is created to add it to the StackSet.

This is what I did:

  1. First create a custom Policy called OrganizationAdministrator with the following policy document:

  {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::*:role/OrganizationAccountAccessRole"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "organizations:ListAccounts",
                "organizations:DescribeOrganization"
            ],
            "Resource": "*"
        }
    ]
  }

  1. Add this Policy to the AWSCloudFormationStackSetAdministrationRole creating it if it does not exist.

  2. Create a new CloudFormation StackSet with the following Properties:

    • AccountInitalization as Name
    • a Template containing all your Profiles
    • OrganizationAccountAccessRole as Execution Role. This Role is automatically generated by Organizations when it creates a new account.
    • AWSCloudFormationStackSetAdministrationRole as Admin Role
    • Add all your existing accounts
  3. Create a New Lambda Function InitiateAccounts with the following Code:


require 'json'

def lambda_handler(event:, context:)
  require 'aws-sdk-organizations' 
  require 'aws-sdk-cloudformation' 

  #First get the accounts already in the stackset
  cloudformation = Aws::CloudFormation::Client.new(region: 'eu-central-1')
  resp = cloudformation.list_stack_instances({ stack_set_name: 'AccountInitalization',})
  stack_set_accounts = []
  resp[:summaries].each do |summary|
    stack_set_accounts << summary.account
  end

  #Iterate over existing accounts and collect accounts to add
  organizations = Aws::Organizations::Client.new(region: 'us-east-1')
  accounts = organizations.list_accounts({})
  orga = organizations.describe_organization({})
  add_accounts = []
  accounts[:accounts].each do |account|
    #First assume role in Account
    next if account.arn == orga[:organization].master_account_arn
    next if account.status == 'SUSPENDED'
    add_accounts << account.id if ! stack_set_accounts.include?(account.id)
  end

  if add_accounts.any? then
    cloudformation.create_stack_instances({
      stack_set_name: "AccountInitalization",
      accounts: add_accounts,
      regions: ['eu-central-1'],
    })
  end

  #return added accounts
  add_accounts
end


  1. Create a SNS Topic OrganizationsCreateAccount with the Lambda Function as Subscriber

  2. Create a Cloudwatch Event Rule OrganizationsCreateAccount with the SNS Topic as Targets and the following Event pattern:


{
  "source": [
    "aws.organizations"
  ],
  "detail-type": [
    "AWS API Call via CloudTrail"
  ],
  "detail": {
    "eventSource": [
      "organizations.amazonaws.com"
    ],
    "eventName": [
      "CreateAccount"
    ]
  }
}

Clemens Bergmann
  • 305
  • 1
  • 4
  • 13
1

I don't think you can refer to an IAM policy in the Master account from your Child accounts. You will have to create the FunctionUserBoundary in each child account.

However that should be done using some automation tools (e.g. CloudFormation, Ansible, or some CI/CD) and whenever you update the master policy file in your central repository it should automatically re-deploy / propagate to all your Organization accounts.

Hope that helps :)

MLu
  • 24,849
  • 5
  • 59
  • 86