aws
Datei mit kms verschlüsseln:
DEK=$(aws kms generate-data-key --key-id ${KMS_KEY_ID} --key-spec AES_128)
DEK_PLAIN=$(echo $DEK | jq -r '.Plaintext' | base64 -d | xxd -p)
DEK_ENC=$(echo $DEK | jq -r '.CiphertextBlob')
# This key must be stored alongside the encrypted artifacts, without it we won't be able to decrypt them
base64 -d <<< $DEK_ENC > key.enc
openssl enc -aes-128-cbc -e -in ${TARGET}.zip -out ${TARGET}.zip.enc -K ${DEK_PLAIN:0:32} -iv 0
hex string is too short, padding with zero bytes to length
task: [artifacts:encrypt] rm -rf ${TARGET}.zip
Datei mit KMS entschlüsseln:
DEK=$(aws kms decrypt --ciphertext-blob fileb://key.enc --output text --query Plaintext | base64 -d | xxd -p)
openssl enc -aes-128-cbc -d -K ${DEK:0:32} -iv 0 -in ${TARGET}.zip.enc -out ${TARGET}.zip
eventbridge.tf:
data "aws_subnet" "subnet_id_A" {
filter {
name = "tag:aws:cloudformation:logical-id"
values = ["PrivateSubnetA"]
}
}
data "aws_subnet" "subnet_id_B" {
filter {
name = "tag:aws:cloudformation:logical-id"
values = ["PrivateSubnetB"]
}
}
data "aws_subnet" "subnet_id_C" {
filter {
name = "tag:aws:cloudformation:logical-id"
values = ["PrivateSubnetC"]
}
}
### Lambda Function
## Create Lambda Role
resource "aws_iam_role" "announcement-nodegroup-rollout" {
name = "announcement-nodegroup-rollout"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
##
## Create LogGroup
resource "aws_cloudwatch_log_group" "announcement-nodegroup-rollout" {
name = "/aws/lambda/announcement-nodegroup-rollout"
retention_in_days = 7
}
resource "aws_iam_policy" "announcement-nodegroup-rollout" {
name = "announcement-nodegroup-rollout"
path = "/"
description = "IAM policy for logging from a lambda"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*",
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:DescribeNetworkInterfaces"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "announcement-nodegroup-rollout" {
role = aws_iam_role.announcement-nodegroup-rollout.name
policy_arn = aws_iam_policy.announcement-nodegroup-rollout.arn
}
##
resource "aws_lambda_function" "announcement-nodegroup-rollout" {
description = "Send Nodegroup Rollout Announcement to Teams"
filename = data.archive_file.lambda_zip.output_path
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
function_name = "announcement-nodegroup-rollout"
role = aws_iam_role.announcement-nodegroup-rollout.arn
timeout = 180
runtime = "python3.12"
handler = "lambda_function.lambda_handler"
memory_size = 256
vpc_config {
subnet_ids = [data.aws_subnet.subnet_id_A.id, data.aws_subnet.subnet_id_B.id, data.aws_subnet.subnet_id_C.id]
security_group_ids = lookup(var.security_group_ids, var.stage)
}
environment {
variables = {
stage = var.stage
webhook_url = var.webhook_url
}
}
tags = {
Function = "announcement-nodegroup-rollout"
Customer = "os/tvnow/systems"
CustomerProject = "r5s-announcements"
}
}
data "archive_file" "lambda_zip" {
type = "zip"
source_dir = "${path.module}/lambda-nodegroup-rollout-source/package"
output_path = "${path.module}/lambda-nodegroup-rollout-source/package/lambda_function.zip"
}
###
resource "aws_lambda_permission" "announcement-nodegroup-rollout" {
statement_id = "AllowExecutionFromEventBridge"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.announcement-nodegroup-rollout.function_name
principal = "events.amazonaws.com"
source_arn = module.eventbridge.eventbridge_rule_arns["logs"]
}
module "eventbridge" {
source = "terraform-aws-modules/eventbridge/aws"
version = "v2.3.0"
create_bus = false
rules = {
logs = {
name = "announcement-UpdateNodegroupVersion"
description = "announcement-UpdateNodegroupVersion"
event_pattern = jsonencode({ "detail" : { "eventName" : ["UpdateNodegroupVersion"] } })
}
}
targets = {
logs = [
{
name = "announcement-UpdateNodegroupVersion"
arn = aws_lambda_function.announcement-nodegroup-rollout.arn
}
]
}
}
lambda_function.py:
import urllib3
import json
import os
class TeamsWebhookException(Exception):
"""custom exception for failed webhook call"""
pass
class ConnectorCard:
def __init__(self, hookurl, http_timeout=60):
self.http = urllib3.PoolManager()
self.payload = {}
self.hookurl = hookurl
self.http_timeout = http_timeout
def text(self, mtext):
self.payload["text"] = mtext
return self
def send(self):
headers = {"Content-Type":"application/json"}
r = self.http.request(
'POST',
f'{self.hookurl}',
body=json.dumps(self.payload).encode('utf-8'),
headers=headers, timeout=self.http_timeout)
if r.status == 200:
return True
else:
raise TeamsWebhookException(r.reason)
def lambda_handler(event, context):
print(event['detail']['requestParameters']['nodegroupName'])
if("r5s-default" not in event['detail']['requestParameters']['nodegroupName']):
return {
'statusCode': 200,
'body': json.dumps('Announcing only default Node Group')
}
stage = os.environ['stage']
webhook_url = os.environ['webhook_url']
f = open("announcement.tpl", "r").read().replace('###STAGE###', stage)
myTeamsMessage = ConnectorCard(webhook_url)
myTeamsMessage.text(f)
myTeamsMessage.send()
announcement.tpl:
<h1><b>r5s Node Rollout gestarted</b></h1>
Soeben wurde auf r5s ###STAGE### ein Node Rollout gestarted (angestoßen durch Updates, Config Changes,...).<br />
Environment Varbales:
stage = dev|preprod|prod
webhook_url: <webhook url>