Изменить группу безопасности по умолчанию, созданную AWS для AWS Active Directory с помощью облачной информации
Когда AWS Active Directory(тип: "AWS::DirectoryService::MicrosoftAD") создается посредством формирования облака, AWS также создает группу безопасности для контроллеров домена. Описание такой группы безопасности "AWS created a security group for d-123456adb directory controllers".
Эта группа безопасности разрешает вход источника как 0.0.0.0/0 для всех портов.
Я должен вручную отредактировать / установить его на свой CIDR vpc после запуска формирования облака, а также я не могу получить его идентификатор внутри формирования облака.
Есть ли способ отредактировать ИЛИ самостоятельно определить группу безопасности при создании Microsoft AD("AWS::DirectoryService::MicrosoftAD") через формирование облака?
3 ответа
Это не совсем то, о чем спрашивали, но это связано и может быть полезно.
Когда создается VPC или другой ресурс, создается система безопасности, которая может иметь слишком разрешительные правила. Как описано на этой странице в разделе "Удалить правило по умолчанию", вы можете удалить правила по умолчанию, указав новые правила. Следующая часть шаблона CloudFormation может помочь удалить старые правила и заменить их чем-то менее разрешительным.
Я обнаружил, что удаление правила выхода 0.0.0.0/0 отлично работает. Он не удаляет входящее правило ссылки на себя для текущей группы безопасности, но это, вероятно, не так важно, как правило выхода.
# Remove default security group rules in the VPC
VpcDefaultSecurityGroupEgressRemove:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId:
Fn::GetAtt: [VPCReference, DefaultSecurityGroup]
IpProtocol: icmpv6
CidrIp: 127.0.0.1/32
Description: Effectively no access
VpcDefaultSecurityGroupIngressRemove:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId:
Fn::GetAtt: [VPCReference, DefaultSecurityGroup]
IpProtocol: icmpv6
CidrIp: 127.0.0.1/32
Description: Effectively no access
Я протестировал это, и он работает нормально. Мне не удалось найти способ удалить все правила группы безопасности в CloudFormation, думаю, это должна быть лямбда.
Шаблон VPC
VPCDefaultSecurityGroup:
Value: !GetAtt VPC.DefaultSecurityGroup
Export:
Name: "VPCDefaultSecurityGroup"
Шаблон группы безопасности
GroupId: !ImportValue VPCDefaultSecurityGroup
Этот ответ является отредактированным ответом службы поддержки AWS на мой запрос, аналогичный вопросу ОП.
В настоящее время эта функция недоступна, и команда разработчиков AWS CloudFormation знает об этой проблеме, и имеется запрос функции.
В качестве обходного пути вы можете использовать пользовательский ресурс с резервной копией Lambda, чтобы получить идентификатор безопасности и передать его в пользовательский ресурс, чтобы к нему можно было получить доступ в стеке CF.
При таком подходе вы создадите функцию Lambda, которая может принимать имя группы безопасности и VPC-id в качестве входных данных и давать идентификатор группы безопасности в качестве выходных данных. Созданный пользовательский ресурс представляет собой фрагмент кода, который сигнализирует лямбда-функции с именем группы и идентификатором VPC. Лямбда возвращает идентификатор группы безопасности этому пользовательскому ресурсу, вы можете получить sg-id, как показано ниже:
{ "Fn::GetAtt" : ["CustomResouce", "security_group_id"] }
Образец шаблона и пример лямбда-функции (для получения идентификатора группы безопасности) включены в конец этого сообщения. В шаблоне функция использовалась при выводе кода, но вы можете использовать то же самое в клиентской группе безопасности, как показано ниже:
"SourceSecurityGroupId" : { "Fn::GetAtt" : ["CustomResouce", "security_group_id"] },
"SourceSecurityGroupName" : { "Fn::Sub": [ "${Alias}_controllers", { "Alias": {"Ref" : "Alias" }} ]},
Пользовательская лямбда-функция customresouce.py (помещается в корзину S3, где Lambda может получить к ней доступ):
import json
import boto3
import time
from botocore.vendored import requests
def lambda_handler(event, context):
print event['RequestType']
try:
if event['RequestType'] == 'Delete':
print "delete"
responseData = {'response': 'Delete'}
responseStatus = 'SUCCESS'
elif event['RequestType'] == 'Create':
print "blabla"
ec2 = boto3.resource('ec2')
vpc = ec2.Vpc(event['ResourceProperties']['vpc'])
security_group_iterator = vpc.security_groups.filter(GroupNames = [event['ResourceProperties']['security_group']])
sg_id = list(security_group_iterator.filter(GroupNames = [event['ResourceProperties']['security_group']]))[0].id
print sg_id
responseData = {'security_group_id': sg_id}
elif event['RequestType'] == 'Update':
print "update"
responseData = {'response': 'Update'}
responseStatus = 'SUCCESS'
responseStatus = 'SUCCESS'
except:
responseStatus = 'FAILED'
responseData = {'FAILED': 'Something bad happened.'}
sendResponse(event, context, responseStatus, responseData)
def sendResponse(event, context, responseStatus, responseData, reason=None, physical_resource_id=None):
responseBody = {'Status': responseStatus,
'Reason': 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
'PhysicalResourceId': physical_resource_id or context.log_stream_name,
'StackId': event['StackId'],
'RequestId': event['RequestId'],
'LogicalResourceId': event['LogicalResourceId'],
'Data': responseData}
print 'RESPONSE BODY:n' + json.dumps(responseBody)
responseUrl = event['ResponseURL']
json_responseBody = json.dumps(responseBody)
headers = {
'content-type' : '',
'content-length' : str(len(json_responseBody))
}
try:
response = requests.put(responseUrl,
data=json_responseBody,
headers=headers)
print "Status code: " + response.reason
except Exception as e:
print "send(..) failed executing requests.put(..): " + str(e)
Пример шаблона, который использует пользовательскую функцию Lambda:
{
"Resources": {
"myDirectory" : {
"Type" : "AWS::DirectoryService::SimpleAD",
"Properties" : {
"Name" : "corp.example.com",
"Password" : "P@ssword",
"Size" : "Small",
"VpcSettings" : {
"SubnetIds" : [ "subnet_value-1", "subnet_value-2" ],
"VpcId" : "your_vpc-id"
}
}
},
"CustomResouce": {
"DependsOn": "myDirectory",
"Type": "Custom::GettingsecuritygroupId",
"Version" : "1.0",
"Properties" : {
"ServiceToken": {"Fn::GetAtt" : ["Mylambda","Arn"]},
"vpc" : "vpc-b0ee43c9",
"security_group" : { "Fn::Sub": [ "${Alias}_controllers", {"Alias":{"Fn::GetAtt" : ["myDirectory","Alias"]} }]}
}
},
"Mylambda":{
"Type" : "AWS::Lambda::Function",
"Properties" : {
"Code" : {
"S3Bucket": "Your_s3_bucket_name",
"S3Key": "customresource.py.zip"
},
"Handler" : "customresource.lambda_handler",
"Role" : "Role_whic_has_permissions_ec2:*",
"Runtime" :"python2.7",
"Timeout" : "60"
}
}
},
"Outputs":{
"SGID" : {
"Value" : { "Fn::GetAtt" : ["CustomResouce", "security_group_id"] }
}
}
}
Скорее глупо, но кажется, что оно может работать как временное решение, пока AWS не приступит к реализации функциональности в своих API /CloudFormation/Hosted AD. ПРИМЕЧАНИЕ. У меня еще не было возможности протестировать вышеизложенное, но я публикую его здесь для ОП и всех, кто может искать решение этой проблемы.
Рекомендации:
Пользовательская ссылка на ресурс
Вот рабочая версия, использующая собственный ресурс с внутренней лямбда-функцией.
lambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub ${prefix}-function
Runtime: python3.9
Role: !GetAtt role.Arn
Handler: index.lambda_handler # default file name of 'index.py', then function name
Timeout: 60
Code:
ZipFile: |
import boto3
import cfnresponse
def lambda_handler(event, context):
print (event['RequestType'])
responseStatus = 'SUCCESS'
try:
if event['RequestType'] == 'Delete':
responseData = {'response': 'Delete'}
elif event['RequestType'] == 'Create':
ec2 = boto3.client('ec2')
groups = ec2.describe_security_groups()
for group in groups['SecurityGroups']:
if(group['GroupName'] == event['ResourceProperties']['security_group_name']):
responseData = {'security_group_id': group['GroupId'] }
elif event['RequestType'] == 'Update':
responseData = {'response': 'Update'}
except Exception as e:
responseStatus = 'FAILED'
responseData = {'FAILED': str(e)}
try:
cfnresponse.send(event, context, responseStatus, responseData)
print ('SUCCESS')
except Exception as e:
print ('FAILURE: ' + str(e))
custom:
Type: Custom::GetDirectorySecurityGroup
Properties:
ServiceToken: !GetAtt lambda.Arn
vpc: !Ref vpc
security_group_name: !Sub ${directory}_controllers
DependsOn:
- directory
- lambda
ingressTCP:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !GetAtt custom.security_group_id # calls custom to get new sg
IpProtocol: tcp
FromPort: 49152
ToPort: 65535
SourceSecurityGroupId: !Ref security # id of other security group
DependsOn:
- security # logical-id of new sg from full cloudformation
- directory # logical-id of ds from full cloudformation
Я публикую это для всех, кто хочет изменить правила входящего трафика для новой службы каталогов. Я пробовал всеми способами получить идентификатор группы безопасности, и это единственный метод, который сработал.