Sunday, June 28, 2020

AWS ABAC

Configuring Policy for AWS Attribute Based Access Control

Below policies are based off of this AWS Tutorial.

Scenario 1: 
  • Allow Action if department tag on the resource does NOT exist.
  • Allow Action if department tag (if exists) matches between resource and principal. 
  • Deny adding or removing department tag unless it matches the principal's
Result:
  • The "aws:RequestTag" condition lets me edit a description of an item that was missing department tag.
  • The "aws:ResourceTag" condition (from empty tag set...)
    • ALLOW create then delete a new tag "DEPT" = "None"
    • ALLOW create then delete a new Tag dEPartment = "IT" (IT is also the principalTag/department) 
    • DENY creation of a new Tag department = "HR"


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllActionsSecretsManagerSameDepartment",
            "Effect": "Allow",
            "Action": "secretsmanager:*",
            "Resource": "*",
            "Condition": {
                "StringLikeIfExists": {
                    "aws:RequestTag/department": "${aws:PrincipalTag/department}",
                    "aws:ResourceTag/department": "${aws:PrincipalTag/department}"
                }
            }
        },
        {
            "Sid": "AllResourcesSecretsManagerNoTags",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetRandomPassword",
                "secretsmanager:ListSecrets"
            ],
            "Resource": "*"
        }
    ]
}

Scenario 2: 
  • Same rule as scenario 1
  • Only Allow HR department (or no department designation) to use secretsmanager 
Result:
  • Only the users whose principalTag/department  is "HR" may use department tag on a secretmanager resource and control it
We had to add lines 10-12 because we can't have same keys at the same level ("aws:RequestTag/department" was already being used on line 14).


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllActionsSecretsManagerSameDepartment",
            "Effect": "Allow",
            "Action": "secretsmanager:*",
            "Resource": "*",
            "Condition": {
                "StringEqualsIfExists": {
                    "aws:RequestTag/department": "HR"
                },
                "StringLikeIfExists": {
                    "aws:RequestTag/department": "${aws:PrincipalTag/department}",
                    "aws:ResourceTag/department": "${aws:PrincipalTag/department}"
                }
            }
        },
        {
            "Sid": "AllResourcesSecretsManagerNoTags",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetRandomPassword",
                "secretsmanager:ListSecrets"
            ],
            "Resource": "*"
        }
    ]
}

Tuesday, June 23, 2020

AWS Policy Conditions

AWS Policy Conditions
References:


Multiple Conditions

Multiple conditions are logical AND
When you are comparing a single KEY to multiple VALUES, then it is logical OR

These two below conditions have similar result:
      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml",
          "aws:RequestTag/department": [
            "HR",
            "IT"
          ]
        }
      }


      "Condition": {
        "StringEquals": {
          "SAML:aud": "https://signin.aws.amazon.com/saml"
        },
        "StringLike": {
          "aws:RequestTag/department": [
            "HR",
            "IT"
          ]
        }
      }

The reason you can't split the first example into two "StringEquals" is because JSON won't permit you to have two identical Keys at the same level. But they would both read as first condition AND second condition where second condition checks if aws:RequestTag/department is HR OR IT.


ForAllValues vs ForAnyValues qualifier 

ForAll works like logical AND to each item in the keys being compared to the keys being compared against. 

"Condition": {
    "ForAllValues:StringEquals": {
        "dynamodb:Attributes": [
            "ID",
            "Message",
            "Tags"
        ]
    }
}

This reads as for all values within dynamodb:Attributes (this is the key being requested in the action) match against this list (we'll call it List B)

Assume the content of dynamdb:Attributes is as follows: [ID,Message,Tags,UserName]. 
So the checks would be
  1. Is there ID in List B : Yes
  2. Is there Message in List B: Yes
  3. Is there Tags in List B: Yes
  4. Is there UserName in List B: No
Because of the 4th check, this returns False.

Assume the content of dynamdb:Attributes is as follows: [ID,Tags]. 
So the checks would be
  1. Is there ID in List B : Yes
  2. Is there Tags in List B: Yes
Because they both return Yes, this returns True.

If dynamdb:Attributes is empty, this also returns True.

Whereas ForAny works like logical OR. Sometimes, this may end with same result.

"Condition": {
    "ForAnyValues:StringEquals": {
        "dynamodb:Attributes": [
            "ID",
            "Message",
            "Tags"
        ]
    }
}

This reads as for any values within dynamodb:Attributes (this is the key being requested in the action) match against this list (we'll call it List B)

Assume the content of dynamdb:Attributes is as follows: [ID,Message,Tags,UserName]. 
So the checks would be
  1. Is there ID in List B : Yes
Because it matches at least one, this returns True.

Assume the content of dynamdb:Attributes is as follows: [ID,Tags]. 
So the checks would be
  1. Is there ID in List B : Yes
Again, at least one is Yes, this returns True.

Assume the content of dynamdb:Attributes is as follows: [UserName,DateStamp]. 

  1. Is there UserName in List B: No
  2. Is there DateStamp in List B: No
Because it could not find any matching items, this returns False.

Although, in this case if dynamdb:Attributes is empty, this will return False.





















Friday, June 19, 2020

AWS DynamoDB + Python

AWS DynamoDB with Python

Create a DynamoDB table as follows:

Table name: TestTable
Primary partition key: TestID (String)

There are two functions.

The updateTable is to update if the key item is found or add if the key is NOT found. It will add the Nickname "column" if it's not already there.

The getContent is to retrieve all content from the table where the nickname is not 'Frank'. The return line also has a condition that if it's empty then return an empty list.  FilterExpression supports various comparison operators including, 'eq' for 'equals'; 'lt' for 'less than'; or 'lte' for 'less than or equal to'

import boto3
from boto3.dynamodb.conditions import Key, Attr
profile = "default"
session = boto3.Session(profile_name=profile)
thisRegion = "us-east-1"
thisResource = session.resource('dynamodb', region_name=thisRegion)

def updateTable(thisId,name):
    table = thisResource.Table('TestTable')
    response = table.update_item(
        Key={
            'TestID': thisId
        },
        UpdateExpression='set Nickname = :nickname',
        ExpressionAttributeValues={
            ':nickname': name
        },
        ReturnValues="UPDATED_NEW"
    )

def getContent(filterString):
    table = thisResource.Table('TestTable')
    response = table.scan(
        FilterExpression=Attr('Nickname').ne(filterString)
    )
    return(response.get('Items',[]))

updateTable('111111','Joe')
updateTable('111121','Frank')
updateTable('111131','Hank')
getContent(filterString='Frank')

Result:

[{'TestID': '111111', 'Nickname': 'Joe'},
 {'TestID': '111131', 'Nickname': 'Hank'}]

Thursday, June 11, 2020

AWS Cloudwatch Cross-Account Cross-Region

AWS Notes

Cloudwatch Cross-Account Cross-Region


By enabling this feature you can create Master-Member relationship to share Cloudwatch data. Any accounts can be set up as master. And in AWS Organization, you can allow any account to have access to list of accounts in your Org. With this enabled, you can switch to view another account's Cloudwatch data and you can also create a Dashboard that contains dataset from any of its member accounts. 




References:

Setup Cloudwatch's Master account(s)

To allow these accounts to obtain list of all accounts in Org. Create this role and policy in the AWS Org's Master account. The name must be exactly as shown. Add the account number of your selected Cloudwatch Master account. 

Policy
Name: CloudWatch-CrossAccountSharing-ListAccounts-Policy
Body:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "organizations:ListAccountsForParent",
                "organizations:ListAccounts"
            ],
            "Resource": "*"
        }
    ]
}

Role
Name: CloudWatch-CrossAccountSharing-ListAccountsRole
Body:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::999999999999:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}


Setup Member account(s)

To expose an account's data, do this for every member account. Add the account number of your selected Cloudwatch Master account.

Role
Name: CloudWatch-CrossAccountSharingRole
Body:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::99999999999:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {}
    }
  ]
}

Choose from these collection of AWS Managed Policies based on your needs
1) Full Read Only:
- arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
- arn:aws:iam::aws:policy/CloudWatchAutomaticDashboardsAccess
- arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
- arn:aws:iam::aws:policy/AWSXrayReadOnlyAccess
2) Both Dashboard and X-Ray
- arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
- arn:aws:iam::aws:policy/CloudWatchAutomaticDashboardsAccess
- arn:aws:iam::aws:policy/AWSXrayReadOnlyAccess
- arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
3) Dashboard only
- arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
- arn:aws:iam::aws:policy/CloudWatchAutomaticDashboardsAccess
4) X-ray only
- arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess
- arn:aws:iam::aws:policy/AWSXrayReadOnlyAccess

Finally, you do this once in every Cloudwatch's Master account. I could not figure out a way to do this programmatically 

  • Cloudwatch
  • Settings
  • Configure Cross-account cross-region
  • Edit cross-account cross-region
  • Select AWS Org selector and Save


Tuesday, June 9, 2020

AWS VPC Data Call

Terraform Notes

VPC Data call

Click Here for TF Reference.

In Terraform you can make Data Call to get information about VPC. Few catches, though...
  • TF limits you to return only exactly 1 matching VPC
  • TF will fail miserable if 0 matching VPC is returned
There are existing arguments, but if you just want the VPC that has a Tag Key, you can do a sub-block of filter.
provider "aws" {
  region   = "us-east-1"
  profile  = "dx"
  insecure = "true"
  alias    = "dx"
}

data "aws_vpc" "this" {
  filter {
    name="tag-key"
    values=["SGCatalog"]
  }
  provider = aws.dx
}

locals {
    VPC_ID = data.aws_vpc.this.id
    SGCatalogItems = split(",",data.aws_vpc.this.tags.SGCatalog)  
}

module "security_groups" {
  source = "make_my_security_groups"
  vpc_id = local.VPC_ID
  sg = local.SGCatalogItems
  providers = {
    aws = aws.dx
  }
}

Monday, June 8, 2020

Inviting AWS SecurityHub Members

Terraform Notes

Security Hub Members

Want to automate inviting members to join the Master account for Security Hub? You can simplify this using AWS Organization.
Because the data call to "aws_organizations_organization" returns a list of map of non_master_accounts, we must first convert this to a map of map.

List of Map                     Map of Map          
 {
    "arn" = ""
    "email" = ""
    "id" = ""
}
 "id" = {
                "arn" = ""
                "email" = ""
                "id" = ""
            }

provider "aws" {
  version = "~> 2.0"
  region  = "us-east-1"
  profile = "master"
}

provider "aws" {
  alias    = "master_east"
  region  = "us-east-1"
  insecure = "true"
  profile = "master"
}

data "aws_organizations_organization" "current" {}
locals {
    all_accounts = {
        for x in data.aws_organizations_organization.current.non_master_accounts: x.id => x
    }  
}
  
resource "aws_securityhub_member" "this" {
    for_each = local.all_accounts
    account_id = each.value["id"]
    email      = each.value["email"]
    invite     = true}
Want to be have another account (not Master of Org) to be the Master of the SecurityHub collection?


provider "aws" {
  version = "~> 2.0"
  region  = "us-east-1"
  profile = "master"
}

provider "aws" {
  alias    = "master_east"
  region  = "us-east-1"
  insecure = "true"
  profile = "master"
}

provider "aws" {
  region   = "us-east-1"
  profile  = "secaudit"
  insecure = "true"
  alias    = "secaudit"
}

##Use the default provider so that we can get ID of ALL Account in the ORG
data "aws_organizations_organization" "master" {}

##Use the SecAudit provider to get the ID of that Account
data "aws_caller_identity" "secaudit" {
    provider  = aws.secaudit

}

##Make a map of all the Account IDs in the Org
locals {
    all_accounts = {
        for x in data.aws_organizations_organization.master.non_master_accounts : x.id => x
    }  
}

##Create invite for SecurityHub Member from SecAudit account to all other Accounts (excluding itself)
resource "aws_securityhub_member" "this" {
    provider  = aws.secaudit
    for_each = {
      for key, value in local.all_accounts:
      key => value
      if key != data.aws_caller_identity.secaudit.account_id
    }
    account_id = each.value["id"]
    email      = each.value["email"]
    invite     = true
} 

AWS WAF log4j query

How to query AWS WAF log for log4j attacks 1. Setup your Athena table using this instruction https://docs.aws.amazon.com/athena/latest/ug/wa...