Удалите шаблон через 5 минут

Этот шаблон создает переменную параметра SSM, а затем пытается удалить ее через 5 минут. Зависимый шаблон не может удалить функцию, поэтому оба стека не могут быть удалены. Я хотел бы знать, как убрать стеки по прошествии времени до жизни (5 минут в данном случае)

AWSTemplateFormatVersion: '2010-09-09'
Description: Demo stack, creates one SSM parameter and gets deleted after 5 minutes.
Resources:
  DemoParameter:
    Type: "AWS::SSM::Parameter"
    Properties:
      Type: "String"
      Value: "date"
      Description: "SSM Parameter for running date command."
      AllowedPattern: "^[a-zA-Z]{1,10}$"
  DeleteAfterTTLStack:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      TemplateURL: 'https://datameetgeobk.s3.amazonaws.com/cftemplates/cfn-stack-ttl_updated.yaml.txt'
      Parameters:
        StackName: !Ref 'AWS::StackName'
        TTL: '5'

Я получил этот шаблон от:

https://aws.amazon.com/blogs/infrastructure-and-automation/scheduling-automatic-deletion-of-aws-cloudformation-stacks/


person shantanuo    schedule 19.12.2019    source источник
comment
Какова ваша актуальная цель? Вы просто хотите создать «временное» значение в хранилище параметров? Это обязательно нужно делать через CloudFormation? Расскажите подробнее о вашем более широком сценарии использования.   -  person John Rotenstein    schedule 20.12.2019
comment
Я покупаю экземпляры на месте, используя шаблоны CFN. Я хочу удалить экземпляры через 1-2 дня. Это сделает это автоматически! Насколько мне известно, невозможно остановить запущенный экземпляр (точечный или другой) ровно через 48 часов. Правильно?   -  person shantanuo    schedule 06.01.2020


Ответы (2)


Кажется, есть много проблем с файлами шаблонов сообщений в блоге. Вы не можете удалить стек, потому что у роли iam во вложенном стеке недостаточно прав для удаления всех ресурсов в стеках (лямбда, роли iam, события, параметры ssm и т. Д.).

Чтобы исправить эту ошибку с разрешениями, вам необходимо создать новый вложенный шаблон с дополнительными разрешениями для вашего DeleteCFNLambdaExecutionRole. Я предоставил обновление с управляемой политикой arn:aws:iam::aws:policy/AdministratorAccess, но я настоятельно рекомендую найти минимальные права для удаления ваших ресурсов. Добавленная мной политика не является хорошей практикой, но, поскольку я не знаю вашего полного варианта использования, это единственный способ гарантировать, что она удалит все.

AWSTemplateFormatVersion: '2010-09-09'
Description: Schedule automatic deletion of CloudFormation stacks
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Input configuration
        Parameters:
          - StackName
          - TTL
    ParameterLabels:
      StackName:
        default: Stack name
      TTL:
        default: Time-to-live
Parameters:
  StackName:
    Type: String
    Description: Stack name that will be deleted.
  TTL:
    Type: Number
    Description: Time-to-live in minutes for the stack.
Resources:
  DeleteCFNLambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service: ["lambda.amazonaws.com"]
          Action: "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AdministratorAccess'
  DeleteCFNLambda:
    Type: "AWS::Lambda::Function"
    DependsOn:
      - DeleteCFNLambdaExecutionRole
    Properties:
      FunctionName: !Sub "DeleteCFNLambda-${StackName}"
      Code:
        ZipFile: |
          import boto3
          import os
          import json

          stack_name = os.environ['stackName']

          def delete_cfn(stack_name):
              try:
                  cfn = boto3.resource('cloudformation')
                  stack = cfn.Stack(stack_name)
                  stack.delete()
                  return "SUCCESS"
              except:
                  return "ERROR" 

          def handler(event, context):
              print("Received event:")
              print(json.dumps(event))
              return delete_cfn(stack_name)
      Environment:
        Variables:
          stackName: !Ref 'StackName'
      Handler: "index.handler"
      Runtime: "python3.6"
      Timeout: "5"
      Role: !GetAtt DeleteCFNLambdaExecutionRole.Arn
  DeleteStackEventRule:
     DependsOn:
       - DeleteCFNLambda
       - GenerateCronExpression
     Type: "AWS::Events::Rule"
     Properties:
       Description: Delete stack event
       ScheduleExpression: !GetAtt GenerateCronExpression.cron_exp
       State: "ENABLED"
       Targets: 
          - 
            Arn: !GetAtt DeleteCFNLambda.Arn
            Id: 'DeleteCFNLambda' 
  PermissionForDeleteCFNLambda: 
    Type: "AWS::Lambda::Permission"
    Properties: 
      FunctionName: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:DeleteCFNLambda-${StackName}"
      Action: "lambda:InvokeFunction"
      Principal: "events.amazonaws.com"
      SourceArn: !GetAtt DeleteStackEventRule.Arn
  BasicLambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal:
            Service: ["lambda.amazonaws.com"]
          Action: "sts:AssumeRole"
      Path: "/"
      Policies:
      - PolicyName: "lambda_policy"
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
          - Effect: "Allow"
            Action:
            - "logs:CreateLogGroup"
            - "logs:CreateLogStream"
            - "logs:PutLogEvents"
            Resource: "arn:aws:logs:*:*:*"
  GenerateCronExpLambda:
    Type: "AWS::Lambda::Function"
    Properties:
      Code:
        ZipFile: |
          from datetime import datetime, timedelta
          import os
          import logging
          import json
          import cfnresponse

          def deletion_time(ttl):
              delete_at_time = datetime.now() + timedelta(minutes=int(ttl))
              hh = delete_at_time.hour
              mm = delete_at_time.minute
              cron_exp = "cron({} {} * * ? *)".format(mm, hh)
              return cron_exp

          def handler(event, context):
            print('Received event: %s' % json.dumps(event))
            status = cfnresponse.SUCCESS
            try:
                if event['RequestType'] == 'Delete':
                    cfnresponse.send(event, context, status, {})
                else:
                    ttl = event['ResourceProperties']['ttl']
                    responseData = {}
                    responseData['cron_exp'] = deletion_time(ttl)
                    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
            except Exception as e:
                logging.error('Exception: %s' % e, exc_info=True)
                status = cfnresponse.FAILED
                cfnresponse.send(event, context, status, {}, None)
      Handler: "index.handler"
      Runtime: "python3.6"
      Timeout: "5"
      Role: !GetAtt BasicLambdaExecutionRole.Arn

  GenerateCronExpression:
    Type: "Custom::GenerateCronExpression"
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt GenerateCronExpLambda.Arn
      ttl: !Ref 'TTL'

После того, как вы внесете это изменение, вам нужно будет загрузить его в s3 и обновить ссылку в основном стеке до вашей версии шаблона.

AWSTemplateFormatVersion: '2010-09-09'
Description: Demo stack, creates one SSM parameter and gets deleted after 5 minutes.
Resources:
  DemoParameter:
    Type: "AWS::SSM::Parameter"
    Properties:
      Type: "String"
      Value: "date"
      Description: "SSM Parameter for running date command."
      AllowedPattern: "^[a-zA-Z]{1,10}$"
    DependsOn: DeleteAfterTTLStack
  DeleteAfterTTLStack:
    Type: "AWS::CloudFormation::Stack"
    Properties:
      TemplateURL: 'https://your-bucket.s3.amazonaws.com/delete_resources.yaml'
      Parameters:
        StackName: !Ref 'AWS::StackName'
        TTL: '5'

Вам может потребоваться добавить поле DependsOn: DeleteAfterTTLStack к каждому ресурсу, чтобы убедиться, что разрешения не удаляются до того, как будут удалены все ресурсы, в противном случае могут возникнуть ошибки разрешений.

Несмотря на то, что это должно работать, я согласен с @John Rotenstein в том, что облачная обработка может быть не лучшим решением. Во-первых, управление разрешениями может быть огромной проблемой. При настройке этого шаблона легко предоставить слишком много или слишком мало разрешений.

person Ben Bloom    schedule 14.01.2020

Простой способ завершить работу экземпляра по истечении заданного периода времени - запустить команду на самом экземпляре, которая находится в спящем режиме на желаемый период, а затем завершает работу экземпляра. Этот сценарий можно передать через данные пользователя.

Прекращение действия может быть выполнено двумя способами:

  • Вариант 1: при запуске экземпляра установите Shutdown behavior = Terminate, а затем попросите сценарий завершить работу экземпляра.
  • Вариант 2. Попросите сценарий получить идентификатор экземпляра через метаданные, затем введите команду terminate-instances, передав идентификатор (для этого метода требуются учетные данные / роль AWS).

Другой популярный метод - создать стопинатор, который представляет собой скрипт или лямбда-функцию, выполняющуюся на регулярной основе, которая проверяет теги на экземплярах, чтобы определить, нужно ли останавливать / завершать экземпляры. Например:

  • Запускать функцию AWS Lambda каждые 6 часов
  • Функция должна проверять все экземпляры, чтобы идентифицировать экземпляры для остановки / завершения на основе тегов, времени работы и т.д. (в основном, все, что вы хотите).
  • Затем функция останавливает / завершает экземпляр (ы)
person John Rotenstein    schedule 06.01.2020
comment
Оба варианта: а) Передача сценария завершения через пользовательские данные. или б) Лямбда-функция для меня слишком сложна. Я действительно хочу, чтобы кто-нибудь объяснил мне, как это сделать, используя вложенные стеки, как описано в этом (официальном) сообщении в блоге. - person shantanuo; 07.01.2020
comment
Использование CloudFormation было бы намного сложнее, чем предлагаемый метод. Например, в Linux это просто вопрос использования sleep 172800; sudo shutdown now -h как части сценария данных пользователя. Этот метод также будет работать для экземпляров, запущенных вне CloudFormation. Однако, если экземпляры запускаются CloudFormation, вероятно, было бы разумно удалить и стек CloudFormation. - person John Rotenstein; 07.01.2020
comment
Что в этом такого сложного? Согласно официальному блогу, запустите его как вложенный стек из основного стека, передав имя родительского стека и желаемое значение TTL. Это так просто, если только это не сработает, и это, кажется, так, потому что никто не ответил даже после предложения награды. Я хочу использовать его для различных целей (особенно во время тренировок). - person shantanuo; 10.01.2020
comment
Я большой поклонник второго подхода. У AWS есть готовый шаблон именно для этой цели: aws.amazon.com/solutions/instance- планировщик. Он позволяет вам установить расписание для ваших экземпляров ec2 и rds. Вы даже можете изменять размер экземпляров по расписанию. Вы также можете сделать это с помощью группы автоматического масштабирования. Если вы создаете AWS::AutoScaling::ScheduledAction ресурс, вы можете управлять мощностью своего экземпляра по расписанию. - person Ben Bloom; 14.01.2020