Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECS Policies #264

Merged
merged 17 commits into from
Feb 23, 2023
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'
tremble marked this conversation as resolved.
Show resolved Hide resolved
- '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)
tremble marked this conversation as resolved.
Show resolved Hide resolved

@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)