Zugegeben, Reverse DNS ist nicht das aufregendste Thema überhaupt, aber es ist in bestimmten Situationen, z. B. bei der Kerberos-Authentifizierung, unerlässlich. Reverse DNS (rDNS) ist der Prozess, bei dem eine IP-Adresse auf einen Hostnamen zurückgeführt wird, was das Gegenteil des häufigeren Forward DNS-Lookups ist, bei dem ein Hostname auf eine IP-Adresse zurückgeführt wird.
AWS aktiviert automatisch die Funktion "Autodefined rules for reverse DNS resolution" für alle VPCs. Diese Funktion erstellt Reverse-DNS-Einträge für alle IP-Adressen innerhalb einer VPC, die wie folgt formatiert sind: ip-192-168-1-40.eu-central-1.compute.internal. Dies ist jedoch für Szenarien wie die Kerberos-Authentifizierung nicht ausreichend, bei denen host.example.com z. B. auf 192.168.1.40 aufgelöst werden sollte und der Reverse-Lookup zurück zu host.example.com anstelle von ip-192-168-1-40.eu-central-1.compute.internal führen sollte.
Die große Herausforderung besteht darin, die Erstellung von PTR-Datensätzen für Reverse-DNS zu automatisieren, idealerweise für eine gesamte AWS-Organisation.
In diesem Artikel werde ich eine Lösung zur Automatisierung der Erstellung von Reverse-DNS-Einträgen (PTR) für eine gesamte AWS-Organisation vorstellen. Immer wenn ein A-Eintrag in einer Route 53 Private Hosted Zone erstellt wird, wird der entsprechende PTR in der Reverse-Lookup-Zone (in-addr.arpa) automatisch generiert. Diese PTR-Datensätze sind in der gesamten AWS-Organisation und, falls gewünscht, auch von lokalen Umgebungen aus zugänglich.
Kurzer Überblick über die Lösung
Ereignisbasierter Aktualisierungsprozess:
1. Eine EventBridge-Regel leitet das Ereignis "ChangeResourceRecordSets" von Route53 an das zentrale Netzwerkkonto weiter.
2. Die Ereignisse werden in einer SQS-Warteschlange gesammelt und von einer Lambda-Funktion verarbeitet.
3. Die Lambda-Funktion prüft, ob es sich bei dem Ereignis um einen A-Datensatz handelt und ob es eine entsprechende Reverse-Lookup-Zone für die IP-Adresse gibt.
4. Je nach Ereignis wird der PTR-Eintrag erstellt oder gelöscht.
Geplanter Aktualisierungsprozess
(Dieser Prozess ist wichtig, um zunächst alle PTRs zu erstellen, wenn bereits A-Datensätze in der AWS-Organisation vorhanden sind)
1. EventBridge plant die Lambda-Funktion im Netzwerkkonto so, dass sie einmal täglich ausgeführt wird.
2. Die Lambda-Funktion erkennt den Detailtyp "Geplantes Ereignis".
3. Die Lambda-Funktion durchläuft alle Konten in der AWS-Organisation und sucht nach Route53 Private Hosted Zones.
4. Alle gefundenen A-Datensätze werden in eine Python-Liste geschrieben.
5. Am Ende wird geprüft, ob für jeden gefundenen A-Eintrag bereits ein PTR vorhanden ist. Wenn nicht, wird eine erstellt.
Auflösen von PTR-Einträgen innerhalb der AWS-Organisation
1. Die Route53 Private Hosted Zones für die Reverse-Lookup-Zonen, z. B. 168.192.in-addr.arpa., sind mit der Network Account VPC verbunden.
2. Das Netzwerkkonto verfügt sowohl über einen Route53 Inbound Resolver als auch über einen Outbound Resolver.
3. Im Netzwerkkonto gibt es eine Route53-Resolver-Regel, die den Outbound-Resolver verwendet und auf die IP-Adresse des Inbound-Resolvers abzielt. Diese Regel wird über den AWS Resource Access Manager (RAM) für die gesamte AWS-Organisation freigegeben.
4. Die Projekt-VPCs sind mit den Route53-Resolver-Regeln verbunden.
5. Infolgedessen werden alle Reverse-DNS-Anfragen für 168.192.in-addr.arpa. an den Inbound Resolver gesendet, der sie auflösen kann.
Auflösen von PTR-Datensätzen von vor Ort
1. Auf dem lokalen DNS-Server ist eine bedingte Weiterleitung konfiguriert, z. B. für 168.192.in-addr.arpa. Das Ziel ist auf den Inbound Resolver eingestellt.
2. Der Inbound Resolver kennt die Route53 Private Hosted Zones, so dass er die PTR-Datensätze auflösen und an den lokalen DNS-Server antworten kann.
Detaillierte Lösung
Einrichten von Route53 Private Hosted Zones für Reverse Lookup Zones
Die Private Hosted Zones (PHZ) für Reverse-DNS-Lookups müssen dem in-addr.arpa-Schema folgen. Das bedeutet, dass der Domänenname aus den IP-Adressblöcken in umgekehrter Reihenfolge besteht, gefolgt von .in-addr.arpa. Zum Beispiel ist 168.192.in-addr.arpa die Reverse-Lookup-Zone für 192.168. Da die CIDR-Notation hier nicht verwendet werden kann, müssen mehrere PHZs erstellt werden, wenn Sie Reverse-Lookup-Zonen nur für bestimmte Subnetze wie 192.168.1.0/24 und 192.168.2.0/24 wünschen.
PHZ for 192.168.1.0/24:
PHZ for 192.168.2.0/24
ReverseLookup1921681:
Type: AWS::Route53::HostedZone
Properties:
HostedZoneConfig:
Comment: "Reverse Lookup Zone for 192.168.1.0/24"
Name: "1.168.192.in-addr.arpa"
VPCs:
- VPCId: !Ref NetworkVpc
VPCRegion: "eu-central-1"
Route53-Resolver Rule und RAM-Freigabe einrichten
Damit VPCs umgekehrte DNS-Einträge (PTR) auflösen können, muss im Netzwerkkonto eine Route53-Auflösungsregel erstellt werden. Diese Regel wird über den AWS Resource Access Manager (RAM) für das gesamte Unternehmen freigegeben. Die Auflösungsregeln müssen mit jeder VPC verknüpft werden, die die Fähigkeit zur umgekehrten Auflösung von DNS-Namen benötigt.
InboundResolverForwardingRuleReverseDNSLookup1921681:
Type: AWS::Route53Resolver::ResolverRule
Properties:
DomainName: "1.168.192.in-addr.arpa."
Name: "1-168-192.in-addr.arpa"
ResolverEndpointId: !Ref OutboundResolverEndpoint
RuleType: FORWARD
TargetIps:
- Ip:
Port: 53
- Ip:
Port: 53
ResolverForwardingRuleShare:
Type: AWS::RAM::ResourceShare
Properties:
AllowExternalPrincipals: False
Name: route-53-resolver-share
Principals:
- !Sub arn:aws:organizations::${OrgAccountId}:organization/${OrgId}
ResourceArns:
- !GetAtt InboundResolverForwardingRuleReverseDNSLookup1921681.Arn
Wichtig! Automatische AWS-Aktivierung von "Autodefined Rules for Reverse DNS Resolution"
AWS aktiviert automatisch die Funktion "Autodefined rules for reverse DNS resolution" für alle VPCs. Diese Funktion finden Sie unter Route 53 -> Resolver -> VPCs.
Daher werden automatisch Reverse-DNS-Einträge für alle IP-Adressen innerhalb einer VPC erstellt, die wie folgt formatiert sind: ip-192-168-1-40.eu-central-1.compute.internal.
nslookup 192.168.1.40
192-168-1-40.in-addr.arpa name = ip-10-0-1-40.eu-central-1.compute.internal.
Das Problem dabei ist, dass diese automatische Auflösung manchmal gegenüber der Route 53-Auflösungsregel bevorzugt wird, wodurch unsere PTRs aus der Private Hosted Zone nicht aufgelöst werden. Um sicherzustellen, dass unsere PTRs aus der Private Hosted Zone korrekt aufgelöst werden, sollte diese Funktion für alle VPCs deaktiviert werden, die unsere Reverse-DNS-Lösung verwenden möchten. Dies kann mit dem folgenden Beispiel-Python-Boto3-Befehl automatisiert werden, der für jede VPC ausgeführt werden kann:
def update_resolver_config(vpcId, r53_client):
try:
resolverConfig = r53_client.get_resolver_config(ResourceId=vpcId)
if resolverConfig['ResolverConfig']['AutodefinedReverse'] != 'DISABLE':
r53_client.update_resolver_config(
ResourceId=vpcId,
AutodefinedReverseFlag='DISABLE'
)
print(f'Reverse DNS lookups disabled for VPC {vpcId}')
except ClientError as e:
print(f'Failed to update resolver config for VPC {vpcId}: {e}')
Erstellung von eingehenden und ausgehenden Resolvern
Die Route 53-Resolver für eingehende und ausgehende Verbindungen sollten im Netzwerkkonto erstellt werden. Außerdem muss die designierte Sicherheitsgruppe den DNS-Port 53 sowohl für TCP- als auch für UDP-Datenverkehr geöffnet haben.
InboundResolverEndpoint:
Type: AWS::Route53Resolver::ResolverEndpoint
Properties:
Direction: INBOUND
IpAddresses:
- SubnetId: !Ref DnsSubnetA
Ip: !GetAtt IPAddressesCustomResource.FifthIpSubnetA
- SubnetId: !Ref DnsSubnetB
Ip: !GetAtt IPAddressesCustomResource.FifthIpSubnetB
Name: inbound-resolver-1
SecurityGroupIds:
- !Ref DnsSecurityGroup
OutboundResolverEndpoint:
Type: AWS::Route53Resolver::ResolverEndpoint
Properties:
Direction: OUTBOUND
IpAddresses:
- SubnetId: !Ref DnsSubnetA
Ip: !GetAtt IPAddressesCustomResource.SixthIpSubnetA
- SubnetId: !Ref DnsSubnetB
Ip: !GetAtt IPAddressesCustomResource.SixthIpSubnetB
Name: outbound-resolver-1
SecurityGroupIds:
- !Ref DnsSecurityGroup
DnsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: String
GroupName: 'DnsSecurityGroup'
SecurityGroupEgress:
- IpProtocol: udp
FromPort: 53
ToPort: 53
CidrIp: 192.168.0.0/16
- IpProtocol: tcp
FromPort: 53
ToPort: 53
CidrIp: 192.168.0.0/16
SecurityGroupIngress:
- IpProtocol: udp
FromPort: 53
ToPort: 53
CidrIp: 192.168.0.0/16
- IpProtocol: tcp
FromPort: 53
ToPort: 53
CidrIp: 192.168.0.0/16
- IpProtocol: icmp
FromPort: -1
ToPort: -1
CidrIp: 192.168.0.0/16
VpcId: !Ref DnsVpc
EventBridge-Regel in allen Konten erstellen
Um die Route53 "ChangeResourceRecordSets"-Ereignisse von allen Konten an das Netzwerkkonto weiterzuleiten, muss in jedem Konto eine EventBridge-Regel erstellt werden. Es ist wichtig, diese Regel in der Region us-east-1 zu erstellen, da Route53 ein globaler Dienst ist und die CloudTrail-Ereignisse von dort ausgehen. Für das EventBridge-Ziel wird das Netzwerkkonto ausgewählt, und es besteht die Möglichkeit, in diesem Stadium eine andere Region zu wählen.
AutomatedPTRforReverseDNSlookup:
Type: "AWS::Events::Rule"
Condition: IsNotNetworkAccount
Properties:
Description: forwards the ChangeResourceRecordSets event to the Network Account
EventPattern:
source:
- "aws.route53"
detail-type:
- "AWS API Call via CloudTrail"
detail:
eventSource:
- "route53.amazonaws.com"
eventName:
- "ChangeResourceRecordSets"
Name: "AutomatedPTRforReverseDNSlookup"
Targets:
- Arn: !Sub "arn:aws:events:eu-central-1:${NetworkAccount}:event-bus/default"
Id: "AutomatedPTRforReverseDNSlookup"
RoleArn: !GetAtt EventBridgeRuleRole.Arn
EventBridgeRuleRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: "EventBridgeRuleRole"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "events.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
RolePolicies:
Type: "AWS::IAM::Policy"
Properties:
PolicyName: "EventBridgeRuleRolePolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "events:PutEvents"
Resource: !Sub "arn:aws:events:eu-central-1:${NetworkAccount}:event-bus/default"
Roles:
- Ref: "EventBridgeRuleRole"
Entwicklung einer zentralen Update-PTR-Logik
Im Netzwerkkonto muss eine EventBridge-Regel für "ChangeResourceRecordSets"-Ereignisse eingerichtet werden. Das Ziel für diese Regel sollte eine SQS-Warteschlange sein. Die Lambda-Funktion wird von dieser SQS-Warteschlange über ein EventSourceMapping ausgelöst.
EventBridge-Regel für ereignisbasierte und geplante:
EventBridgeRule:
Type: "AWS::Events::Rule"
Properties:
Description: "Create a PTR record in reverse DNS zones whenever an A record in a PHZ is created, modified, or deleted."
State: ENABLED
EventPattern: !Sub
- |
{
"source": [
"aws.route53"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"route53.amazonaws.com"
],
"eventName": [
"ChangeResourceRecordSets"
]
}
}
- { eventNames: !Join [ '", "', !Ref Events ] }
Name: AutomatedPTRforReverseDNSlookup
Targets:
- Arn: !GetAtt SQSQueue.Arn
Id: AutomatedPTRforReverseDNSlookup
ScheduledEventBridgeRule:
Type: "AWS::Events::Rule"
Properties:
Description: "Checks once a day if all PTR Records are set up correctly"
State: ENABLED
ScheduleExpression: !Ref Schedule
Name: !Sub "AutomatedPTRforReverseDNSlookupScheduled"
Targets:
- Arn: !GetAtt SQSQueue.Arn
Id: AutomatedPTRforReverseDNSlookup
SQS Queue:
SQSQueue:
Type: "AWS::SQS::Queue"
Properties:
QueueName: AutomatedPTRforReverseDNSlookup
MessageRetentionPeriod: 1000
ReceiveMessageWaitTimeSeconds: 0
VisibilityTimeout: 950
SQSQueuePolicy:
Type: "AWS::SQS::QueuePolicy"
Properties:
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Id": "${SQSQueue.Arn}/SQSDefaultPolicy",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": "sqs:SendMessage",
"Resource": "${SQSQueue.Arn}",
"Condition": {
"ArnEquals": {
"aws:SourceArn": [
"${CloudWatchRule.Arn}",
"${ScheduledCloudWatchRule.Arn}"
]
}
}
}
]
}
Queues:
- !Ref SQSQueue
Lambda Function, Lambda Role und EventSourceMapping:
LambdaFunction:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: AutomatedPTRforReverseDNSlookup
Description: Creates a PTR record in reverse DNS zones when an A record in a PHZ is created, modified, or deleted.
Handler: !Sub ${PythonFileName}.lambda_handler
Role: !GetAtt LambdaRole.Arn
MemorySize: 128
Timeout: 900
Runtime: "python3.12"
Code:
S3Bucket: !Ref S3Bucket
S3Key: !Ref S3Key
Environment:
Variables:
LambdaRole: !Ref CrossAccountLambdaRole
OrganizationAccountId: !Ref OrganizationAccount
ReverseLookupZone1921681Id: !Ref ReverseLookupZone1921681
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: AutomatedPTRforReverseDNSlookupRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: AutomatedPTRforReverseDNSlookupRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
Resource: "*"
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- Fn::Sub: 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*'
- Effect: Allow
Action:
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
Resource: !Sub "arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:AutomatedPTRforReverseDNSlookup"
- Effect: Allow
Action:
- sts:AssumeRole
Resource: !Sub "arn:aws:iam::*:role/${CrossAccountLambdaRole}"
- Effect: "Allow"
Action:
- route53:ChangeResourceRecordSets
- route53:ListResourceRecordSets
- route53:GetHostedZone
Resource:
- !Sub "arn:aws:route53:::hostedzone/${ReverseLookupZone1921681}"
- Effect: Allow
Action:
- logs:CreateLogDelivery
- logs:DeleteLogDelivery
Resource: "*"
EventSourceMapping:
Type: "AWS::Lambda::EventSourceMapping"
Properties:
BatchSize: 10
Enabled: true
EventSourceArn: !GetAtt SQSQueue.Arn
FunctionName: !Ref LambdaFunction
Die Lambda-Funktion verarbeitet CloudTrail-Ereignisse für die Aktion "ChangeResourceRecordSets". Sie prüft, ob das Ereignis einen A-Datensatz beinhaltet und ob die IP-Adresse innerhalb einer der vordefinierten Route53 Private Hosted Zones (PHZ) für Reverse-Lookup liegt. Wenn die IP-Adresse übereinstimmt, erstellt oder löscht die Funktion den entsprechenden PTR-Eintrag auf der Grundlage der Ereignisaktion.
Außerdem verarbeitet der Lambda ein geplantes Ereignis, das täglich von EventBridge ausgelöst wird. Dieses geplante Ereignis durchläuft alle Konten in der AWS-Organisation, um Route53 Private Hosted Zones zu finden. Es sammelt alle A-Datensätze in einer Python-Liste. Am Ende der Iteration prüft der Lambda, ob für jeden gefundenen A-Datensatz ein PTR-Datensatz existiert; falls nicht, wird einer erstellt.
Nachfolgend finden Sie den Python-Code für die Lambda-Funktion:
import json
import boto3
import os
from ipaddress import ip_address
from botocore.exceptions import ClientError
# Environment variables for the zone IDs
REVERSELOOKUPZONE1921681ID = os.environ['ReverseLookupZone1921681Id']
# Environment variable for ORG AccountID
ORGACCOUNTID = os.environ['OrganizationAccountId']
# Mapping IP prefixes to zone IDs
zone_mapping = {
'192.168.1': REVERSELOOKUPZONE10200ID
}
# Initialize the Route53 client
route53_client = boto3.client('route53')
def lambda_handler(event, context):
messages = [json.loads(record['body']) for record in event['Records']]
for message in messages:
try:
cleanedEvent = json.loads(message['Message'])
except:
cleanedEvent = message
print(f'CleanedEvent: {cleanedEvent}')
if cleanedEvent["detail-type"] == "AWS API Call via CloudTrail":
print('API Call')
# Nur aufrufen, wenn der Event ein A-Record betrifft
if is_a_record_event(cleanedEvent):
handle_called_event(cleanedEvent, context)
elif cleanedEvent["detail-type"] == "Scheduled Event":
print('Scheduled')
handle_scheduled_event(cleanedEvent, context)
def is_a_record_event(event_detail):
eventName = event_detail['detail']['eventName']
if eventName == 'ChangeResourceRecordSets':
changes = event_detail['detail']['requestParameters']['changeBatch']['changes']
for change in changes:
if change.get('resourceRecordSet', {}).get('type') == 'A':
return True
return False
def handle_called_event(event, context):
eventName = event['detail']['eventName']
if eventName == 'ChangeResourceRecordSets':
changes = event['detail']['requestParameters']['changeBatch']['changes']
for change in changes:
action = change['action']
resource_record_set = change.get('resourceRecordSet', {})
resource_records = resource_record_set.get('resourceRecords', [])
dns_name = resource_record_set.get('name', 'Unknown DNS Name')
for record in resource_records:
ip_address = record['value']
record_info = {'DNS Name': dns_name, 'IP Address': ip_address}
if action == 'CREATE':
manage_ptr_record(record_info, action='CREATE')
elif action == 'DELETE':
manage_ptr_record(record_info, action='DELETE')
def manage_ptr_record(record_info, action):
ip_addr_str = record_info['IP Address']
dns_name = record_info['DNS Name']
if not ip_addr_str.startswith(('192.168.1'')):
print(f'The IP {ip_addr_str} is not in the valid range.')
return
zone_prefix = ip_addr_str.split('.')[1]
zone_id = zone_mapping.get('192.' + zone_prefix)
if not zone_id:
print(f"No zone ID found for the IP prefix 192.{zone_prefix}.")
return
ip_blocks = ip_addr_str.split('.')
reversed_ip_blocks = ip_blocks[::-1]
reversed_ip = '.'.join(reversed_ip_blocks) + '.in-addr.arpa.'
ptr_record_name = dns_name
# Überprüfe, ob der PTR-Eintrag bereits existiert
paginator = route53_client.get_paginator('list_resource_record_sets')
record_exists = False
try:
for page in paginator.paginate(HostedZoneId=zone_id):
for record_set in page['ResourceRecordSets']:
if (record_set['Type'] == 'PTR' and
record_set['Name'].rstrip('.') == reversed_ip.rstrip('.') and
any(rr['Value'].rstrip('.') == ptr_record_name.rstrip('.') for rr in record_set.get('ResourceRecords', []))):
record_exists = True
break
if record_exists:
# Schleife verlassen, wenn der Eintrag gefunden wurde
break
except ClientError as e:
print(f"An error occurred during PTR record check: {e}")
return
if not record_exists and action == 'DELETE':
print(f"No existing PTR record for {ip_addr_str} to delete.")
return
# If it does not exist and the action is CREATE, or if it exists and the action is DELETE, implement the change.
if (not record_exists and action == 'CREATE') or (record_exists and action == 'DELETE'):
change_batch = {
'Comment': f'{action} PTR record for {ip_addr_str}',
'Changes': [{
'Action': action,
'ResourceRecordSet': {
'Name': reversed_ip,
'Type': 'PTR',
'TTL': 300,
'ResourceRecords': [{'Value': ptr_record_name}]
}
}]
}
try:
response = route53_client.change_resource_record_sets(
HostedZoneId=zone_id,
ChangeBatch=change_batch
)
print(f'Successfully {action} PTR record for {ip_addr_str} to name {ptr_record_name} : {response}')
except ClientError as e:
print(f'An error occurred: {e}')
else:
if action == 'CREATE':
print(f"PTR record for {ip_addr_str} to {ptr_record_name} already exists. Skipping CREATE.")
elif action == 'DELETE':
print(f"PTR record for {ip_addr_str} to {ptr_record_name} does not exist. Skipping DELETE.")
def handle_scheduled_event(event, context):
# List to store all A-Record data
a_records_list = []
## Iterate through all accounts
for accountId in get_accounts():
print(f'############## CHECKING Account {accountId} ##############')
region = 'eu-central-1'
roleName = os.environ['LambdaRole']
route53_client = get_session(accountId, region, roleName).client('route53')
# Paginate through all the hosted zones
hosted_zones_paginator = route53_client.get_paginator('list_hosted_zones')
for hosted_zones_page in hosted_zones_paginator.paginate():
for hosted_zone in hosted_zones_page['HostedZones']:
hosted_zone_id = hosted_zone['Id']
print(f'############## Checking Hosted Zone {hosted_zone_id} ##############')
record_sets_paginator = route53_client.get_paginator('list_resource_record_sets')
for record_sets_page in record_sets_paginator.paginate(HostedZoneId=hosted_zone_id):
for record_set in record_sets_page['ResourceRecordSets']:
if record_set['Type'] == 'A': # Check for 'A' records
# Use get() with a default value to avoid KeyError
resource_records = record_set.get('ResourceRecords', [])
# Store the A-Record data in the list
for ip_record in resource_records:
a_records_list.append({
'DNS Name': record_set['Name'],
'IP Address': ip_record['Value']
})
print(f"A-Record found: {record_set['Name']} - {ip_record}")
# Process each A-Record in the list using the function 'manage_ptr_record'
for a_record in a_records_list:
manage_ptr_record(a_record, action='CREATE')
def get_accounts():
roleName = os.environ['LambdaRole']
org_client = get_session(ORGACCOUNTID, 'eu-central-1', roleName).client('organizations')
accountList = []
accountPaginator = org_client.get_paginator('list_accounts')
accountIterator = accountPaginator.paginate()
for accounts in accountIterator:
for account in accounts['Accounts']:
if account['Status'] == "ACTIVE":
accountList.append(account['Id'])
return accountList
def get_session(accountId, region, roleName):
sts_client = boto3.client('sts')
assumed_role_object = sts_client.assume_role(
RoleSessionName='xyz', RoleArn=f'arn:aws:iam::{accountId}:role/{roleName}')
credentials = assumed_role_object['Credentials']
access_key_id = credentials['AccessKeyId']
secret_access_key = credentials['SecretAccessKey']
session_token = credentials['SessionToken']
new_session = boto3.Session(
aws_access_key_id=access_key_id,
aws_secret_access_key=secret_access_key,
aws_session_token=session_token,
region_name=region
)
return new_session
Die IAM-Rolle für jedes Konto, das von der Lambda-Funktion im Netzwerkkonto für den täglichen Planer verwendet wird, erfordert die folgenden Berechtigungen:
ReverseDNSLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: CrossAccountReverseDNSLambdaRoleRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub 'arn:aws:iam::${NetworkAccountId}:root'
Action:
- sts:AssumeRole
MaxSessionDuration: 3600
Path: /
Policies:
- PolicyName: CrossAccountReverseDNSLambdaRoleRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- organizations:ListAccounts
- organizations:DescribeAccount
Resource: "*"
- Effect: Allow
Action:
- route53:ListResourceRecordSets
- route53:GetHostedZone
- route53:ListHostedZones
Resource: "*"
- Effect: Allow
Action:
- iam:PassRole
Resource: 'arn:aws:iam::*:role/*'
Schlussbemerkungen
Einige der CloudFormation-Stacks müssen als StackSets in der gesamten AWS-Organisation bereitgestellt werden. Daher wird empfohlen, Tools wie CfCT oder LZA, zu verwenden, insbesondere wenn ControlTower im Einsatz ist.
Ich hoffe, ich konnte eine mögliche Lösung zur Automatisierung der Erstellung von Reverse-DNS-Einträgen (PTR) in einer gesamten AWS-Organisation aufzeigen. Darüber hinaus habe ich gezeigt, wie die Reverse-DNS-Einträge innerhalb der AWS-Organisation und von vor Ort aufgelöst werden können.