AWS cross account break glass

Yurii Martyniuk
7 min readJul 9, 2024

--

⚠️ The Break Glass IAM user is a critical, long-term credential. Monitoring and alerting mechanisms are essential to prevent misuse.

⚠️ Warning ⚠️ The break glass user in this example uses the IAMFullAccess managed policy which is NOT least priviledge. This can be changed according to your organizations security requirements :note: IAM events are Global Service Events and are captured in Cloudtrail logs in the us-east-1 region. It is important that the EventBridge code is deployed in us-east-1 in order to process the logs and send notifications successfully. https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-concepts.html#cloudtrail-concepts-global-service-events

Introduction

The organization management account is often used to provide break glass access to AWS accounts within an organization. Break glass (which draws its name from breaking the glass to pull a fire alarm) refers to a quick means for a person who does not have access privileges to certain AWS accounts to gain access in exceptional circumstances by using an approved process.

The use cases for break glass access include:

  • Failure of the organization’s Identity Provider (IdP).
  • A security incident involving the organizations’ IdP(s).
  • A failure involving IAM Identity Center.
  • A disaster involving the loss of an organization’s entire cloud or IdP teams.

The break glass IAM user is a long term credential and is extremely important that access to these roles is monitored, and alarms and alerts are triggered when the roles are used to access the environment in order to prevent misuse.

The Break Glass User

For customers using IAM Identity Center for the Single Sign On (SSO) of workforce identities in AWS, an external IdP is recommended. In the unfortunated circumstance where SSO integration is unavailable, it is advised to have a Break Glass user created in Identity and Access Managment (IAM). This user can be used to gain administrative access to your AWS environment during an emergency when SSO is not available.

Since the Break Glass user is only needed in case of emergency, it will be implemented in a single AWS account so that it may be tightly controlled. The Break Glass user may access other accounts through the ‘SwitchRole’ mechanism.

Alerting is enabled that provides a notification when somebody logs in as the Break Glass user or when the Break Glass user uses the SwitchRole mechanism. Notification in this example uses email for delivery, though the alert could be delivered via a different method.

Solution Architecture

This solution is made up of 5 components:

  • Break Glass User: An IAM user is an entity in AWS that represents a human user. The Break Glass user is deployed in the management (or security) account and is authorized to assume the Break Glass Role in other accounts using the SwitchRole mechanism.
  • Break Glass Role: A role specifies a set of permissions that you can use to access AWS resources that you need. When the Break Glass User assumes the Break Glass Role in another account, its original permissions are temporarily set aside and it is granted the permissions specified in the Break Glass Role configured in the target account.
  • EventBridge: Amazon EventBridge is a serverless service that uses events to trigger actions. In this use case, the EventBridge is used to trigger an SNS notification.
  • Amazon SNS: Amazon Simple Notification Service (SNS) is a messaging service that provides message delivery from publishers to subscribers. In this use case, EventBridge is the publisher and email is the subscriber.
  • AWS KMS AWS Key Management Service (KMS) is an AWS managed service that allows you to create and control cryptographic keys used for encryption.

When a user in the organization logs into the management (or security) account as the Break Glass User, they are provided access assuming they have the proper credentials. This login activity creates an authentication event which is captured via EventBridge and a notification is sent via SNS.

Deployment Instructions

  • Deploy breakglassuser.tf into the account where the break glass user will reside. This can be deployed in the management account, though AWS recommends deploying the user in a security account or dedicated account. You will need to update the file with the email address of where the notification will be sent. We recommend using an email distribution list to ensure notification coverage.
data "aws_caller_identity" "current" {}
locals {
account_id = data.aws_caller_identity.current.account_id
}

variable "emailAddress" {
type = string
description = "Enter the email address to subscribe to the SNS notification"
}

//Creates a Breakglass User
resource "aws_iam_user" "bguser" {
name = "BreakglassUser"
}
/* Assigning IAM Full Access to the breakglass user on the account where it's deployed
The code currently uses the AWS managed IAMFullAccess policy to ensure that the Breakglass User has sufficient permissions to be used in case of an emergency.
This is NOT a least privileged policy and can be changed according to Organization's security requirements.
*/
resource "aws_iam_user_policy_attachment" "IAMAccess" {
user = aws_iam_user.bguser.name
policy_arn = "arn:aws:iam::aws:policy/IAMFullAccess"
}
// Policy which allows the IAM User to perform a switch role to the BreakGlassRole

resource "aws_iam_policy" "BreakGlassAssumeRole" {
name = "BreakGlassAssumeRole"
description = "BreakGlassAssumeRole"

policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Resource = "arn:aws:iam::*:role/BreakGlassRole"
},
]
})
}
resource "aws_iam_user_policy_attachment" "assume-role" {
user = aws_iam_user.bguser.name
policy_arn = aws_iam_policy.BreakGlassAssumeRole.arn
}

// Cloudwatch Alarm for breakglass user login

resource "aws_cloudwatch_event_rule" "login-event" {
name = "capture-breakglass-user-sign-in"
description = "Capture breakglass user AWS Console Sign In"

event_pattern = <<EOF
{
"detail-type": ["AWS Console Sign In via CloudTrail"],
"source": ["aws.signin"],
"detail": {
"eventSource": ["signin.amazonaws.com"],
"eventName": ["ConsoleLogin"],
"userIdentity": {
"type": ["IAMUser"],
"userName": ["BreakglassUser"]
}
}
}
EOF
}

resource "aws_cloudwatch_event_target" "login-target" {
rule = aws_cloudwatch_event_rule.login-event.name
target_id = "SendToSNS"
arn = aws_sns_topic.aws_logins.arn
}

// Cloudwatch Alarm for breakglass user switch role

resource "aws_cloudwatch_event_rule" "switch-event" {
name = "capture-breakglass-user-switch-role"
description = "Capture breakglass user switching roles"

event_pattern = <<EOF
{
"source": ["aws.signin"],
"detail-type": ["AWS Console Sign In via CloudTrail"],
"detail": {
"eventSource": ["signin.amazonaws.com"],
"eventName": ["SwitchRole"],
"userIdentity": {
"type": ["IAMUser"],
"userName": ["BreakglassUser"]
}
}
}
EOF
}

resource "aws_cloudwatch_event_target" "switch-target" {
rule = aws_cloudwatch_event_rule.switch-event.name
target_id = "SendToSNS"
arn = aws_sns_topic.aws_logins.arn
}

// Cloudwatch Alarm for breakglass user assume role

resource "aws_cloudwatch_event_rule" "assume-event" {
name = "capture-breakglass-user-assume-role"
description = "Capture breakglass user assuming roles via the CLI"

event_pattern = <<EOF
{
"source": ["aws.sts"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["sts.amazonaws.com"],
"eventName": ["AssumeRole"],
"userIdentity": {
"type": ["IAMUser"],
"userName": ["BreakglassUser"]
}
}
}
EOF
}

resource "aws_cloudwatch_event_target" "assume-target" {
rule = aws_cloudwatch_event_rule.assume-event.name
target_id = "SendToSNS"
arn = aws_sns_topic.aws_logins.arn
}

//SNS topic creation
resource "aws_sns_topic" "aws_logins" {
name = "breakglassuser-console-logins"
kms_master_key_id = "alias/breakglassSNS"
}

resource "aws_sns_topic_subscription" "sns-topic" {
topic_arn = aws_sns_topic.aws_logins.arn
protocol = "email"
endpoint = var.emailAddress
}

resource "aws_sns_topic_policy" "default" {
arn = aws_sns_topic.aws_logins.arn
policy = data.aws_iam_policy_document.sns_topic_policy.json
}

data "aws_iam_policy_document" "sns_topic_policy" {
statement {
effect = "Allow"
actions = ["SNS:Publish"]

principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}

resources = [aws_sns_topic.aws_logins.arn]
}
}

/* Optional Customer CMK
SNS allows encryption at rest for its topic. If SNS uses the default AWS Key Management Service (AWS KMS) key alias/aws/sns for this encryption, then CloudWatch alarms can't publish messages to the SNS topic.
The default AWS KMS key's policy for SNS doesn't allow CloudWatch alarms to perform kms:Decrypt and kms:GenerateDataKey API calls. Because this key is AWS managed, you can't manually edit the policy.
If the SNS topic must be encrypted at rest, then use a customer managed key.
*/

resource "aws_kms_key" "kmskey" {
description = "BreakGlass SNS Topic"
deletion_window_in_days = 10
policy = data.aws_iam_policy_document.keypolicy.json
enable_key_rotation = true
}
resource "aws_kms_alias" "alias" {
name = "alias/breakglassSNS"
target_key_id = aws_kms_key.kmskey.key_id
}

// The key policy can be different based on your organizational standards. Below policy here provides full access to the key by the 'ROOT' user whose usage is strongly discouraged.
data "aws_iam_policy_document" "keypolicy" {
statement {
sid = "allow_events_to_decrypt_key"
effect = "Allow"
resources = ["*"]

actions = [
"kms:GenerateDataKey*",
"kms:Decrypt",
]

principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}
}

statement {
sid = "Enable IAM User Permissions"
effect = "Allow"
resources = ["*"]
actions = ["kms:*"]

principals {
type = "AWS"
identifiers = ["arn:aws:iam::${local.account_id}:root"]
}
}
}
  • Deploy breakglassrole.tf into all other accounts. This is the role that the break glass user will assume. The role in this file assigns IAMFullAccess which is NOT a least priviledged policy. This can be changed according to your organizations security requirements.
variable "AccoundID" {
type = number
description = "Enter the AWS account ID where the BreakGlassUser is deployed"
}

resource "aws_iam_role" "BreakGlassRole" {
name = "BreakGlassRole"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
AWS = "arn:aws:iam::${var.AccoundID}:user/BreakglassUser"
}
},
]
})
}

/* Assigning IAM Full Access to the breakglass user on the account where it's deployed
The code currently uses the AWS managed IAMFullAccess policy to ensure that the Breakglass User has sufficient permissions to be used in case of an emergency.
This is NOT a least privileged policy and can be changed according to Organization's security requirements.
*/

resource "aws_iam_role_policy_attachment" "BreakGlassRole-test-role-policy-attach" {
role = aws_iam_role.BreakGlassRole.name
policy_arn = "arn:aws:iam::aws:policy/IAMFullAccess"
}

After Deployment

  • Enable Multi Factor Authentication (MFA).
  • Setup and vault the password.

--

--

Yurii Martyniuk
Yurii Martyniuk

Written by Yurii Martyniuk

AWS | DevOps | Infrastructure-as-Code

No responses yet