Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions aws/policy/paas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,38 @@ Statement:
StringLike:
lambda:FunctionArn:
- arn:aws:lambda:{{ aws_region }}:{{ aws_account_id }}:function:*

- Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurFees
Effect: Allow
Action:
- ecs:CreateCluster
Resource: "*"

- Sid: AllowGlobalUnrestrictedResourceActionsWhichIncurNoFees
Effect: Allow
Action:
- ecs:Describe*
- ecs:List*
- ecs:TagResource
- ecs:UntagResource
- ecs:PutAccountSetting
- ecs:RegisterTaskDefinition
- ecs:DeregisterTaskDefinition
Resource:
- "*"

- Sid: AllowGlobalRestrictedResourceActionsWhichIncurFees
Effect: Allow
Action:
- ecs:RunTask
- ecs:StartTask
- ecs:StopTask
- ecs:DeleteCluster
- ecs:CreateService
- ecs:DeleteService
- ecs:UpdateService
- ecs:UpdateCluster
- ecs:*CapacityProvider
- ecs:PutClusterCapacityProviders
Resource:
- 'arn:aws:ecs:{{ aws_region }}:{{ aws_account_id }}:*'
32 changes: 7 additions & 25 deletions aws/policy/security-services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,11 @@ Statement:
- 'arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole'
- 'arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole'
- 'arn:aws:iam::aws:policy/service-role/AWSServiceRoleForVPCTransitGateway'

# Legacy - We need to backport ansible-collections/community.aws/63 or
# wait until community.aws drops CI support for Ansible 2.9
- Sid: AllowPassRole
Effect: Allow
Action:
- iam:PassRole
Resource:
- 'arn:aws:iam::{{ aws_account_id }}:role/ansible_lambda_role'
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

- Sid: AllowRegionalUnrestrictedResourceActionsWhichIncurNoFees
Effect: Allow
Action:
- iam:ListAccountAliases
- iam:ListPolicies
- iam:ListInstanceProfiles
- iam:GetUser
- acm:ListCertificates
- acm:ListTagsForCertificate
Expand All @@ -73,12 +62,7 @@ Statement:
Action:
- access-analyzer:ValidatePolicy
- iam:GetRole
- iam:ListAttachedRolePolicies
- iam:ListRoles
- iam:ListRolePolicies
- iam:ListRoleTags
- iam:ListSAMLProviders
- iam:ListServerCertificates
- iam:List*
- iam:TagRole
- iam:UntagRole
- kms:CreateAlias
Expand All @@ -92,12 +76,7 @@ Statement:
- kms:GetKeyPolicy
- kms:GetKeyRotationStatus
- kms:GetPublicKey
- kms:ListAliases
- kms:ListGrants
- kms:ListKeyPolicies
- kms:ListKeys
- kms:ListResourceTags
- kms:ListRetirableGrants
- kms:List*
- kms:PutKeyPolicy
- kms:RetireGrant
- kms:ScheduleKeyDeletion
Expand Down Expand Up @@ -152,7 +131,6 @@ Statement:
- iam:GetInstanceProfile
- iam:GetSAMLProvider
- iam:GetServerCertificate
- iam:ListInstanceProfilesForRole
- iam:PassRole
- iam:RemoveRoleFromInstanceProfile
- iam:UpdateSAMLProvider
Expand Down Expand Up @@ -181,6 +159,7 @@ Statement:
- 'arn:aws:iam::{{ aws_account_id }}:role/rds_export_task'
- 'arn:aws:logs:{{ aws_region }}:{{ aws_account_id }}:log-group:*'
- 'arn:aws:logs:{{ aws_region }}:{{ aws_account_id }}:log-group:ansible-test*'
- 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS'

# This allows AWS Services to autmatically create their Default Service Linked Roles
# These have fixed policies and can only be assumed by the service itself.
Expand All @@ -195,6 +174,7 @@ Statement:
- 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/eks-nodegroup.amazonaws.com/*'
- 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/transitgateway.amazonaws.com/*'
- 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/network-firewall.amazonaws.com/*'
- 'arn:aws:iam::{{ aws_account_id }}:role/aws-service-role/ecs.amazonaws.com/*'
Condition:
ForAnyValue:StringEquals:
iam:AWSServiceName:
Expand All @@ -204,3 +184,5 @@ Statement:
- 'eks-nodegroup.amazonaws.com'
- 'transitgateway.amazonaws.com'
- 'network-firewall.amazonaws.com'
- 'ecs.amazonaws.com'
- 'ecs-test.amazonaws.com'
130 changes: 129 additions & 1 deletion aws/terminator/paas.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime
from datetime import datetime, timedelta

from . import DbTerminator, Terminator

Expand Down Expand Up @@ -117,3 +117,131 @@ def terminate(self):
else:
# delete streaming distribution
self.client.delete_streaming_distribution(Id=self.Id, IfMatch=ETag)


class Ecs(DbTerminator):
@property
def age_limit(self):
return datetime.timedelta(minutes=20)

@property
def name(self):
return self.instance['clusterName']

@staticmethod
def create(credentials):
def _paginate_cluster_results(client):
names = client.get_paginator('list_clusters').paginate(
PaginationConfig={
'PageSize': 100,
}
).build_full_result()['clusterArns']

if not names:
return []

return client.describe_clusters(clusters=names)['clusters']

return Terminator._create(credentials, Ecs, 'ecs', _paginate_cluster_results)

def terminate(self):
def _paginate_task_results(container_instance=None):
params = {
'cluster': self.name,
'PaginationConfig': {
'PageSize': 100,
}
}

if container_instance:
params['containerInstance'] = container_instance

names = self.client.get_paginator('list_tasks').paginate(
**params
).build_full_result()['taskArns']

return [] if not names else names

def _paginate_task_definition_results():
names = self.client.get_paginator('list_task_definitions').paginate(
PaginationConfig={
'PageSize': 100,
}
).build_full_result()['taskDefinitionArns']

return [] if not names else names

def _paginate_container_instance_results():
names = self.client.get_paginator('list_container_instances').paginate(
cluster=self.name,
PaginationConfig={
'PageSize': 100,
}
).build_full_result()['containerInstanceArns']

return [] if not names else names

def _paginate_service_results():
names = self.client.get_paginator('list_services').paginate(
cluster=self.name,
PaginationConfig={
'PageSize': 100,
}
).build_full_result()['serviceArns']

return [] if not names else names

# If there are running services, delete them first
services = _paginate_service_results()
for each in services:
self.client.delete_service(cluster=self.name, service=each, force=True)

# Deregister container instances and stop any running task
container_instances = _paginate_container_instance_results()
for each in container_instances:
self.client.deregister_container_instance(containerInstance=each['containerInstanceArn'], force=True)

# Deregister task definitions
task_definitions = _paginate_task_definition_results()
for each in task_definitions:
self.client.deregister_task_definition(taskDefinition=each)

# Stop all the tasks
tasks = _paginate_task_results()
for each in tasks:
self.client.stop_task(cluster=self.name, task=each)

# Delete cluster
try:
self.client.delete_cluster(cluster=self.name)
except (self.client.exceptions.ClusterContainsServicesException, self.client.exceptions.ClusterContainsTasksException):
pass


class EcsCluster(DbTerminator):
@property
def age_limit(self):
return timedelta(minutes=30)

@property
def name(self):
return self.instance['clusterName']

@staticmethod
def create(credentials):
def _paginate_cluster_results(client):
names = client.get_paginator('list_clusters').paginate(
PaginationConfig={
'PageSize': 100,
}
).build_full_result()['clusterArns']

if not names:
return []

return client.describe_clusters(clusters=names)['clusters']

return Terminator._create(credentials, EcsCluster, 'ecs', _paginate_cluster_results)

def terminate(self):
self.client.delete_cluster(cluster=self.name)