Using AWS Config as a dedicated account in an Organization

Soner Kalayci
zoiwrites
Published in
6 min readOct 16, 2020
Photo by Luca Bravo on Unsplash

Authors: Malte Brodersen, Soner Kalayci

Migrating to the cloud is at full speed, and even big enterprises have already partially or completely switched to the Cloud.

However, a topic that needs more attention is Security. Although the Cloud is designed to be secure, misconfigured resources still pose a serious threat. Once compromised, the whole infrastructure is in danger.

If I were one of our enterprise customers, I’d ask myself: is there a fast and easy way to see possible threats for all my resources across all of my cloud accounts? “Sure”, a consultant might say, “But they are not suited to check your specific resources.” Practically, that means that the Security checks only check for generic threats.

In AWS, the Config Service is a tool that can check for compliances in your AWS account. Compliance in this case means that you can define a rule and see if your resources are following this rule or not. These might be rules that check if your access credentials were rotated recently or if EBS Volumes for your EC2 Instances are encrypted.
If these rules are too generic for you, you can define your own custom rules backed by a Lambda script and deploy it to your AWS account. With this feature comes basically unlimited potential.

I intentionally wrote “AWS account” in the singular form because you need to deploy every rule in each of your AWS accounts one by one. As we all know, Enterprise customers have a lot of AWS accounts. And you sure don’t want to deploy every rule in every account.

That’s why we were trying to get AWS Config to work with AWS Organizations for one of our big enterprise customers. For this, we have a separate Member account of the AWS Organization. This account is dedicated to contain the AWS Config rules and roll it out to all other Member accounts of the Organization. This way, it is possible to keep the billing, organization and security separated from each other, which gives you more control over each account.

We struggled a bit to get this to work in combination with customized Config rules since it’s a fairly new feature and, admittedly, a very specific setup. So getting help from the documentation or Online Forums will not work this time. That’s why we decided to write this blog article.

So please allow us to introduce: How to Set up a separated AWS Config account in an AWS Organization.

Our requirements

  • The rules should be defined in a separate account (not the AWS Organization Master) for security reasons.
  • All Organizational resources and compliance statuses should be in a single place.
  • As we have more complex rules, custom rules need to be working in the environment.
  • The settings should be enforced by AWS Organisation.

Alternative solutions

For us, the major requirement is the Organization integration and enforcement. If this is not strongly required, a valid alternative could be found here.

From the Compliance perspective, limiting the access for the StackSets needs to be considered. It would be also possible for the “config-admin” to provision other resources as well.

The environment

In our example, we have an enterprise typical account structure with dedicated account for each task (logging, billing, shared services etc.). For simplicity, we only consider the required accounts. accounts like logging, etc. will not be shown even if strongly recommended.

Example account structure

Managing rules

As defined in the AWS Config documentation (here) it is possible to delegate the permissions to manage rules for a dedicated account. This reduces the number of people interacting with the AWS Organization Master account, which is always a good idea.

To delegate the Config rule permissions to another account, you have to follow the steps below.

In the Orga-Master (#111111111111), run

$ aws organizations register-delegated-administrator — service-principal=config-multiaccountsetup.amazonaws.com — account-id=”222222222222"

You can list the delegated Administrator account for validation:

$ aws organizations list-delegated-administrators — service-principal=config-multiaccountsetup.amazonaws.com

In the Config-Master (#222222222222), create an IAM role for the Lambda execution and attach the proper policies.

$ aws iam create-role — role-name svc-lambda — assume-role-policy-document file:///home/zoi/aws-config/iam/lambda_policy.json$ aws iam create-policy — policy-name svc-config-put-evaluations — policy-document file:///home/zoi/aws-config/iam/config_put_evaluations.json$ aws iam attach-role-policy — role-name svc-lambda — policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole$ aws iam attach-role-policy — role-name svc-lambda — policy-arn arn:aws:iam::222222222222:policy/svc-config-put-evaluations

The policy document for the role policy (lambda_policy.json):

{
"Version": "2012–10–17",
"Statement": [{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}]
}

The policy document for putting Evaluations via Lambda looks like this (config_put_evaluations.json):

{
"Version": "2012–10–17",
"Statement": [{
"Sid": "ConfigPutEvaluations",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"config:PutEvaluations"
],
"Resource": "*"
}]
}
The AWS Console with the IAM role for invoking Lambda functions

AWS Config is providing the details for the evaluated resource to Lambda via the Handler. Therefore, these two policies for the role are sufficient for a working environment.

For our custom managed rules, we created a Lambda script as follows in the Config Master account (#222222222222).

$ aws lambda update-function-code — function-name config-evaluate-custom-tags — zip-file fileb:///home/zoi/aws-config/lambda/config-evaluate-custom-tags.zip

Accessing Results

To collect the results, we can use normal aggregator methods. Unfortunately, aggregation without explicit permission is only possible in the AWS Organization Master account. Although this is not our preferred solution, we will use it here as an example.

In the Orga-Master (#111111111111)

The creation of an aggregator in AWS Config
Enabling all regions for the aggregator in the AWS Config Console

The challenge

If we do not check out a member account in the orga, we should already see the inherited Config rule (Prefixed with “OrgConfigRule-”)

In the Member #1 (#333333333)

If we try to evaluate the rule, we will see quickly that this does not behave as it should.

A custom organization Config rule without the correct permissions doesn’t show results

The reason why this happens is that the Lambda function tries to write back the compliance results to an object, which does not exist in the “config-master” account.

This requires us to use a little trick.

In the Member #1 (#333333333)

In the sub accounts, we have to create an IAM role that is allowed to be assumed by the “config-master” and is allowed to write back evaluation results to Config.

Update the existing AWS Config role by adding the entity to the Trust Relationship as follows:

{
"Version": "2012–10–17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::222222222222:root"
},
"Action": "sts:AssumeRole"
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "config.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]}

The result should look like this:

The trust relationship of the Config role in member accounts

To allow Lambda to assume this role, we have also to extend it a little in the config-master account (#22222222222)

Update the Lambda IAMs role policy to:

{
"Version": "2012–10–17",
"Statement": [{
"Sid": "ConfigPutEvaluations",
"Effect": "Allow",
"Action": [
"sts:AssumeRole",
"config:PutEvaluations"
],
"Resource": "*"
}]
}

To make use of this role, we have to modify the Lambda a little as well.

By adding the following lines, we tell Lambda to assume the role in the member account and then — within this context — write back the results.

evaluation = evaluate_compliance(configuration_item, rule_parameters)sts_client = boto3.client("sts")
assumedRoleObject = None
credentials = None
try:
assumedRoleObject = sts_client.assume_role(
RoleArn=event["executionRoleArn"],
RoleSessionName="AWSConfigPutEvaluation"
)
credentials = assumedRoleObject['Credentials']except Exception as e:
logger.error("Error while assuming the role")
logger.error(e)

try:
session = boto3.Session(
aws_access_key_id=credentials["AccessKeyId"],
aws_secret_access_key=credentials["SecretAccessKey"],
aws_session_token=credentials["SessionToken"]
)
config = session.client('config', 'eu-central-1')
config.put_evaluations(
Evaluations=[{
"ComplianceResourceType":
configuration_item["resourceType"],
"ComplianceResourceId":
configuration_item["resourceId"],
"ComplianceType":
evaluation["compliance_type"],
"Annotation":
evaluation["annotation"],
"OrderingTimestamp":
configuration_item["configurationItemCaptureTime"]
}],
ResultToken=result_token
)
except TypeError as e:
logger.error("Could not assume the role")
logger.error(e)

If we evaluate the rule a second time, everything should work out smoothly.

After adjusting the Lambda function, the rule works and shows us the compliance status

--

--