[PYTHON] About launching an instance with an encrypted EBS volume (where I was addicted)

I summarized it because there was a part I was addicted to when I tried to automatically start an instance with an encrypted EBS root volume using Lambda.

EBS root volume encryption

EBS currently supports encryption of the root volume of an instance, as described in the article below. http://aws.typepad.com/aws_japan/2015/12/new-encrypted-ebs-boot-volumes.html This time, I will write about the points I was addicted to when automatically starting an instance with this root volume encryption.

Instance startup failure

This time I was trying to automate the launch of an instance using AWS Lambda. The script used is the following instance startup batch created based on Lambda function (python) that takes AMI backup. You can also find it on GitHub along with the stop. https://github.com/tatsuo48/Hello-world/tree/master/LambdaFunctions

startinstance.py


#!/usr/bin/python
# -*- coding: utf-8 -*-

import json

import boto3

import pprint

TAG_KEY_AUTO_START = 'auto-start'


print('Loading function')

pp = pprint.PrettyPrinter(indent=4)

#Function name: lambda_handler
def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))

    ec2_client   = boto3.client('ec2')

    ret = execute_start_instance(ec2_client)
    print 'Start instance success(%s).' % (ret)

    return 0
    raise Exception('Something went wrong')

#Function name: execute_start_instance
#Return value: Execution result
#Arguments: ec2_client
#       : ec2_resource
#Function: Start an instance.
def execute_start_instance(ec2_client):
    response = ec2_client.describe_instances()

    result = None
    for ec2_group in response['Reservations']:
        for instance_info in ec2_group['Instances']:
            ret = is_target(instance_info)
            
            if (ret == False):
                continue
            instance_id = instance_info.get('InstanceId')
            response = ec2_client.start_instances(InstanceIds=[instance_id,])
            print response
            result = True
    return result

#Function name: is_target
#Return value: Whether to start
#Arguments: instance_info <dict>
#Function: Judge whether startup is necessary
def is_target(instance_info):
    val = get_tag_value(
        instance_info,
        TAG_KEY_AUTO_START
    )

    if val is None:
        return False

    return True

#Function name: get_tag_value
#Return value: Tag value (None if there is no match for the key)
#Arguments: instance_info <dict>
#       : key <str>
#Function: Get the tag value of the specified key from the instance information
def get_tag_value(instance_info, key):
    tags = instance_info.get('Tags')
    if tags == None:
        return None

    for tag in tags:
        if not (key == tag['Key']):
            continue

        tag_value = tag['Value']
        if tag_value == "true":
            return True

    return None

However, no matter how many times I executed the Lambda function, the instance did not start even though the correct response was returned as below. .. .. ..

{u'StartingInstances': [{u'InstanceId': 'Instance ID', u'CurrentState': {u'Code': 0, u'Name': 'pending'}, u'PreviousState': {u'Code': 80, u'Name': 'stopped'}}], 'ResponseMetadata': {'HTTPStatusCode': 200, 'RequestId': 'kkksfh084k-l9hh-8iy6-hshs4-ipsug88w9hwh'}}

Cause: Insufficient permissions for the execution role

I did a lot of research, but the cause was very simple. The execution permission of KMS (Key Management Service) was missing. .. This time, I created and used the encryption key myself instead of the default key. In that case, it was necessary to allow the use of the key by the "key user" of the corresponding encryption key or the policy of the execution role. If you want to set it as the "key user" of the encryption key, you can set it with the GUI as follows. 暗号化キーのキーユーザ設定.png

The execution role policy would be like this.

When setting in the execution role policy


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1236596007000",
            "Effect": "Allow",
            "Action": [
                "kms:*"
            ],
            "Resource": [
                "ARN of the created key"
            ]
        }
    ]
}

At the end

The cause is quite natural, but it is difficult to get to that point if it is a function that you do not normally use. I thought that I should continue to touch functions that I haven't touched, both inside and outside the business.

Recommended Posts

About launching an instance with an encrypted EBS volume (where I was addicted)
Where I was worried about heroku
Two things I was happy about with Python 3.9
I was addicted to scraping with Selenium (+ Python) in 2020
What I was careful about when implementing Airflow with docker-compose
What I was worried about when displaying images with matplotlib
I was addicted to not being able to get an email address from google with django-allauth authentication
What I was addicted to with json.dumps in Python base64 encoding
A note I was addicted to when creating a table with SQLAlchemy
I was addicted to confusing class variables and instance variables in Python
I thought a Python class variable was an instance variable and died