Closed aaditunni-unityinfotech closed 1 year ago
I will take a look at this, seems like it has matched the wrong resource in Terraform.
This has been fixed locally and will be released in the next version soon. Until now here is your template:
$ cf2tf aws-ecr-continuouscompliance-v1.yaml
// Converting aws-ecr-continuouscompliance-v1.yaml to Terraform!
// Existing Terraform src code found at /tmp/terraform_src.
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
resource "aws_cloudwatch_event_rule" "capture_ecr_image_scan_events" {
description = "Capture ECR Scan Events and Trigger an Action"
event_pattern = {
detail-type = [
"ECR Image Scan"
]
source = [
"aws.ecr"
]
}
name = "CaptureECRScanEvent"
// CF Property(State) = "ENABLED"
// CF Property(Targets) = [
// {
// Arn = aws_lambda_function.ecr_to_sec_hub_send_findings_lambda.arn
// Id = "IDCaptureECRImageScanEvents"
// }
// ]
}
resource "aws_lambda_function" "ecr_to_sec_hub_send_findings_lambda" {
function_name = "ECR2SecurityHubSendFindingsLambda"
description = "Maps ECR Scan Finding into ASFF before importing to Security Hub"
handler = "index.lambda_handler"
memory_size = 384
role = aws_iam_role.ecr_to_sec_hub_send_findings_lambda_role.arn
runtime = "python3.7"
timeout = 70
environment {
variables = {
account_num = data.aws_caller_identity.current.account_id
region = data.aws_region.current.name
}
}
code_signing_config_arn = {
ZipFile = "import json
import boto3
import datetime
import uuid
import os
def lambda_handler(event, context):
# import Lambda ENV VARs
accountId = os.environ['account_num']
awsRegion = os.environ['region']
# Get ECR event details
eventDetails = event['detail']
repoName = eventDetails['repository-name']
findingsevcounts = eventDetails['finding-severity-counts']
numCritical = 0
numMedium = 0
numHigh = 0
if findingsevcounts.get('CRITICAL'):
numCritical = findingsevcounts['CRITICAL']
if findingsevcounts.get('MEDIUM'):
numMedium = findingsevcounts['MEDIUM']
if findingsevcounts.get('HIGH'):
numHigh = findingsevcounts['HIGH']
# send finding to Security Hub
severity = "LOW"
title = "ECR Finding"
ECRComplianceRating = 'PASSED'
if numMedium:
severity = "MEDIUM"
title = "Medium ECR Vulnerability"
ECRComplianceRating = 'FAILED'
if numHigh:
severity = "HIGH"
title = "High ECR Vulnerability"
ECRComplianceRating = 'FAILED'
if numCritical:
severity = "CRITICAL"
title = "Critical ECR Vulnerability"
ECRComplianceRating = 'FAILED'
# ISO Time
iso8061Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
# ASFF BIF Id
asffID = str(uuid.uuid4())
# import security hub boto3 client
sechub = boto3.client('securityhub')
# call BIF
try:
response = sechub.batch_import_findings(
Findings=[
{
'SchemaVersion': '2018-10-08',
'Id': asffID,
'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + accountId + ':product/' + accountId + '/default',
'ProductFields': {
'ECRRepoName': repoName,
},
'GeneratorId': asffID,
'AwsAccountId': accountId,
'Types': [ 'Software and Configuration Checks' ],
'FirstObservedAt': iso8061Time,
'UpdatedAt': iso8061Time,
'CreatedAt': iso8061Time,
'Severity': {
'Label': severity
},
'Title': title,
'Description': title,
'Resources': [
{
'Type': 'AwsEcr',
'Id': 'AWS::::Account:' + accountId,
'Partition': 'aws',
'Region': awsRegion,
}
],
'WorkflowState': 'NEW',
'Compliance': {'Status': ECRComplianceRating},
'RecordState': 'ACTIVE'
}
]
)
print(response)
except Exception as e:
print(e)
print("Submitting finding to Security Hub failed, please troubleshoot further")
raise
"
}
}
resource "aws_iam_role" "ecr_to_sec_hub_send_findings_lambda_role" {
force_detach_policies = [
{
PolicyName = "ECRToSecHubSendFindingsLambda-Policy"
PolicyDocument = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"cloudwatch:PutMetricData",
"securityhub:BatchImportFindings"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "*"
}
]
}
}
]
assume_role_policy = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = [
"sts:AssumeRole"
]
}
]
}
}
resource "aws_lambda_permission" "permission_for_events_to_invoke_lambdachk" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.ecr_to_sec_hub_send_findings_lambda.arn
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.capture_ecr_image_scan_events.arn
}
resource "aws_lambda_function" "create_security_hub_custom_action_target_lambda" {
function_name = "CreateSecurityHubCustomActionTargetLambda-ECR"
description = "Custom resource to create an action target in Security Hub"
handler = "index.lambda_handler"
memory_size = 256
role = aws_iam_role.create_security_hub_custom_action_target_lambda_role.arn
runtime = "python3.7"
timeout = 60
environment {
variables = {
Region = data.aws_region.current.name
}
}
code_signing_config_arn = {
ZipFile = "import boto3
import cfnresponse
import os
def lambda_handler(event, context):
try:
properties = event['ResourceProperties']
region = os.environ['Region']
client = boto3.client('securityhub', region_name=region)
responseData = {}
if event['RequestType'] == 'Create':
response = client.create_action_target(
Name=properties['Name'],
Description=properties['Description'],
Id=properties['Id']
)
responseData['Arn'] = response['ActionTargetArn']
elif event['RequestType'] == 'Delete':
account_id = context.invoked_function_arn.split(":")[4]
client.delete_action_target(
ActionTargetArn=f"arn:aws:securityhub:{region}:{account_id}:action/custom/{properties['Id']}"
)
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, {})
"
}
}
resource "aws_iam_role" "create_security_hub_custom_action_target_lambda_role" {
force_detach_policies = [
{
PolicyName = "CreateActionTarget-LambdaPolicy-ECR"
PolicyDocument = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"cloudwatch:PutMetricData"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"securityhub:CreateActionTarget",
"securityhub:DeleteActionTarget"
]
Resource = "*"
}
]
}
}
]
assume_role_policy = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = [
"sts:AssumeRole"
]
}
]
}
}
resource "aws_cloudwatch_event_rule" "ecr_access_prohibited_rule" {
name = "ECRAccessProhibitedRule"
description = "ECR1 - Deny Access to ECR due to vulnerability assesment"
event_pattern = {
source = [
"aws.securityhub"
]
detail-type = [
"Security Hub Findings - Custom Action"
]
resources = [
aws_securityhub_action_target.ecr_action_target.arn
]
}
// CF Property(State) = "ENABLED"
// CF Property(Targets) = [
// {
// Arn = aws_lambda_function.ecr_access_prohibited_lambda.arn
// Id = "ECR1"
// }
// ]
}
resource "aws_securityhub_action_target" "ecr_action_target" {
// CF Property(ServiceToken) = aws_lambda_function.create_security_hub_custom_action_target_lambda.arn
name = "ECR1"
description = "Deny Access to ECR"
identifier = "ECR11"
}
resource "aws_lambda_permission" "ecr_access_prohibited_lambda_permission" {
function_name = aws_lambda_function.ecr_access_prohibited_lambda.arn
action = "lambda:InvokeFunction"
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.ecr_access_prohibited_rule.arn
}
resource "aws_lambda_function" "ecr_access_prohibited_lambda" {
function_name = "ECRAccessProhibitedLambda"
description = "ECR1 - Deny Access to ECR due to vulnerability assesment"
handler = "index.lambda_handler"
memory_size = 256
role = aws_iam_role.ecr_access_prohibited_lambda_role.arn
runtime = "python3.7"
timeout = 60
code_signing_config_arn = {
ZipFile = "import boto3
import json
import os
def lambda_handler(event, context):
repoName = str(event['detail']['findings'][0]['ProductFields']['ECRRepoName'])
ecr = boto3.client('ecr')
try:
policyText = '{\n "Version" : "2008-10-17",\n "Statement" : [ {\n "Sid" : "deny all",\n "Effect" : "Deny",\n "Principal" : "*",\n "Action" : [ "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:BatchCheckLayerAvailability" ]\n } ]\n}'
response = ecr.set_repository_policy(
repositoryName=repoName,
policyText=policyText
)
except Exception as e:
print(e)
print("SSM automation execution error")
raise
"
}
}
resource "aws_iam_role" "ecr_access_prohibited_lambda_role" {
force_detach_policies = [
{
PolicyName = "ECRAccessProhibitedLambdaPolicy"
PolicyDocument = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"cloudwatch:PutMetricData"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"ssm:StartAutomationExecution",
"ecr:*",
"iam:PassRole",
"securityhub:UpdateFindings"
]
Resource = "*"
}
]
}
}
]
assume_role_policy = {
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
Action = [
"sts:AssumeRole"
]
}
]
}
}
There will likely be things that need manually fixed, feel free to open up new issues =)
Thanks
I was trying to convert a CloudFormation template to terraform and it gave me this error: ValueError: Could not convert Cloudformation property "AvailabilityZone" to Terraform attribute of ['id'].
Traceback (most recent call last): File "", line 198, in _run_module_as_main
File "", line 88, in _run_code
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Scripts\cf2tf.exe__main.py", line 7, in
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\click\core.py", line 1130, in call
return self.main(*args, kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\click\core.py", line 1055, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\click\core.py", line 1404, in invoke
return ctx.invoke(self.callback, ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\click\core.py", line 760, in invoke
return callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\app.py", line 44, in cli
config = TemplateConverter(tmpl_path.stem, cf_template, search_manger).convert()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\convert.py", line 92, in convert
tf_resources = self.convert_to_tf(self.manifest)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\convert.py", line 139, in convert_to_tf
tf_resources.extend(converter(resources))
^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\convert.py", line 316, in convert_resources
resolved_values = self.resolve_values(
^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\convert.py", line 172, in resolve_values
data[key] = self.resolve_values(
^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\convert.py", line 184, in resolve_values
return allowed_func[key](self, value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\aadit.unni\AppData\Local\Programs\Python\Python311\Lib\site-packages\cf2tf\conversion\expressions.py", line 421, in get_att
raise ValueError(
ValueError: Could not convert Cloudformation property "AvailabilityZone" to Terraform attribute of ['id'].
Here is the link to the template: https://github.com/aws-samples/aws-securityhub-remediations/blob/main/aws-ecr-continuouscompliance/cft/aws-ecr-continuouscompliance-v1.yaml
Link to the official blog: https://aws.amazon.com/blogs/containers/automating-image-compliance-for-amazon-eks-using-amazon-elastic-container-registry-and-aws-security-hub/