おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

AWS CLIで存在するNode.js 10.xのLambda関数を一覧する

[要対応] AWS Lambda における Node.js 10 のサポート終了 | [Action Required] AWS Lambda end of support for Node.js 10 のメール来てるけど、どこにあるんだとおもったら

tl;dr

以下を実行

REGIONS=`aws ec2 describe-regions --query 'Regions[*].RegionName' --output text`
for region in $REGIONS; do
  aws lambda list-functions \
    --function-version ALL \
    --region $region \
    --query "Functions[?Runtime=='nodejs10.x']"
    --no-cli-pager
done
  • region一覧とって回そう
  • --function-version ALLLATEST 以外のバージョンも取得する
  • 見つかったら、CloudWatch MetricでInvocationされているかを確認して、使われてなかったら削除しよう

AWS Configでリソースに紐付かないセキュリティグループを抽出

tl;dr

  • 使っていないセキュリティグループを列挙したい
  • セキュリティグループはENIに対して割り当て、ENIがEC2などのリソースにアタッチされている。使っていないセキュリティグループ = どのENIにも割り当てられていないセキュリティグループ、なのだが、取得するのはセキュリティグループを列挙し、ENIを列挙して、という作業が必要でEC2 API叩いて処理するの地味に面倒
  • AWS Configを有効にしているなら、クエリでいい感じにとれるし、リージョンもまたげるし、Aggregatorを使っているならマルチアカウントも一発

コード

import json

import boto3

client = boto3.client('config')

query = "SELECT resourceId, awsRegion, resourceName, " \
        "configuration.description, configuration.ipPermissions, " \
        "configuration.ipPermissionsEgress, relationships " \
        "WHERE resourceType = 'AWS::EC2::SecurityGroup'"

results = []

response = client.select_resource_config(Expression=query, 
                                         Limit=100)
results.extend(response['Results'])

while True:
    if 'NextToken' in response:
        response = client.select_resource_config(Expression=query,
                                                 NextToken=response['NextToken'], 
                                                 Limit=100)
        results.extend(response['Results'])
    else:
        break

for result in results:
    result = json.loads(result)

    for relationship in result['relationships']:
        if relationship['resourceType'] == 'AWS::EC2::NetworkInterface':
            #eni_id = relationship['resourceId']
            break
    else:
        # 関連するENIが無い = リソースに関連付けられていないセキュリティグループ
        print('\t'.join(
            [result['awsRegion'], result['resourceId'], result['resourceName'],
             result['configuration']['description']]))

マルチアカウント版コード

select_aggregate_resource_config() に差し替えるだけで、AWS Config Aggregatorに対してクエリを実行できます。便利。

import json

import boto3

client = boto3.client('config')

query = "SELECT accountId, resourceId, awsRegion, resourceName, " \
        "configuration.description, configuration.ipPermissions, " \
        "configuration.ipPermissionsEgress, relationships " \
        "WHERE resourceType = 'AWS::EC2::SecurityGroup'"

results = []

response = client.select_aggregate_resource_config(Expression=query, Limit=100,
                                                   ConfigurationAggregatorName='<aggregator name>')
results.extend(response['Results'])

while True:
    if 'NextToken' in response:
        response = client.select_aggregate_resource_config(Expression=query, 
                                                           NextToken=response['NextToken'], 
                                                           Limit=100,
                                                           ConfigurationAggregatorName='<aggregator name>')
        results.extend(response['Results'])
    else:
        break

for result in results:
    result = json.loads(result)

    for relationship in result['relationships']:
        if relationship['resourceType'] == 'AWS::EC2::NetworkInterface':
            #eni_id = relationship['resourceId']
            break
    else:
        # 関連するENIが無い = リソースに関連付けられていないセキュリティグループ
        print('\t'.join(
            ['"' + result['accountId'] + '"', result['awsRegion'], result['resourceId'], 
             result['resourceName'], result['configuration']['description']]))

VPCのサブネットを抽出して、きれいに並べたい

tl;dr

aws ec2 describe-subnets --filter Name=vpc-id,Values=vpc-123456  \
  --query "Subnets[*].[CidrBlock,(Tags[?Key=='Name'].Value)[0]]" \
  --output text | sort -V
10.0.0.0/22     public-subnet-ap-northeast-1a
10.0.4.0/22     public-subnet-ap-northeast-1c
10.0.8.0/22     public-subnet-ap-northeast-1d
10.0.12.0/22    private-subnet-ap-northeast-1a
10.0.16.0/22    private-subnet-ap-northeast-1c
10.0.20.0/22    private-subnet-ap-northeast-1d

aws ec2 describe-subnets

タグを取り出すのがちょっとだるい

{
  "Subnets": [
    {
      "AvailabilityZone": "ap-northeast-1d",
      "AvailabilityZoneId": "apne1-az2",
      "AvailableIpAddressCount": 1019,
      "CidrBlock": "10.0.20.0/22",
      "State": "available",
      "SubnetId": "subnet-...",
      "VpcId": "vpc-....",
      "Tags": [
        {
          "Key": "Name",
          "Value": "private-subnet-ap-northeast-1d"
        }
      ],
    },
   ...

今回は指定したVPC内のサブネットと、その名前を取り出したかったので、CidrBlockと、Tags の中の KeyName である要素をフィルタしてきて、これは1つなので (正確には1つかゼロ)、リストの先頭をとってくる。

--query "Subnets[*].[CidrBlock,(Tags[?Key=='Name'].Value)[0]]"

sort -V

queryの中で sort_by を使ってソートも (きっと) できるけれど、さすがに辛いので、sort を使う。

-V は natural sort of (version) numbers within text ということで、ドットで区切られたバージョン番号をソートするオプションで、バージョン番号ではないけれど、ドットの後の数字で並べてくれるので、これでIPアドレス順に並んでくれる。

fishでAWS Organizations配下のアカウントに同じコマンドを投げるスクリプト

環境調査のためにOrganization配下のAWSアカウントすべてにコマンド実行したいということがあったりする。fishを使っているので、関数を作って使っているのでメモ。

~/.config/fish/functions/ 配下に maws.fish としてつくる

function maws
  set accounts (aws organizations list-accounts --query 'Accounts[].Id' --output text | string match -ra '\d+')
  echo "call aws command in these accounts: $accounts"

  for account in $accounts
    echo "[$account]"

    set assumerole (aws sts assume-role --role-arn arn:aws:iam::$account:role/OrganizationAccountAccessRole --role-session-name (whoami))

    if test $status -eq 0
      set -x AWS_ACCESS_KEY_ID (echo $assumerole | jq -r '.Credentials.AccessKeyId')
      set -x AWS_SECRET_ACCESS_KEY (echo $assumerole | jq -r '.Credentials.SecretAccessKey')
      set -x AWS_SESSION_TOKEN (echo $assumerole | jq -r '.Credentials.SessionToken')

      aws $argv
    end

    echo ""

    set -e AWS_ACCESS_KEY_ID
    set -e AWS_SECRET_ACCESS_KEY
    set -e AWS_SESSION_TOKEN
  end

end

一旦、 ふつうのaws cli

aws ec2 describe-vpcs --query Vpcs[].[OwnerId,VpcId,CidrBlock] --output text

といった感じで単一アカウントで確認してOKだったら

maws ec2 describe-vpcs --query Vpcs[].[OwnerId,VpcId,CidrBlock] --output text

とするだけ。

動作の補足

環境変数に認証情報が存在すると、優先順位として強いので、Organizationの親アカウントの認証情報をもって実行し、Assume Roleして、環境変数をセット、削除するという流れ

jq 使ったら負けだよなと思いつつ、手抜き。

USB-C to SATA変換ケーブルが便利

早いストレージをそこそこ用意するとき、裸のSSDを使うことがあります。また、ポータブルHDDを壊れて、バラして中の2.5インチハードディスクを使うと普通に使えるといったことも割りとあり、そういった場合、従来はUSB3.0SATA変換ケーブルを利用していました。

USB3.0SATA変換ケーブルの問題点

USB端子1つから取れる電流では、特にハードディスクは稼働しないため、

  • データ用のUSB端子と別に電源用のUSB端子を接続する
  • 別にACアダプタがつく

といった製品が多かったです。ACアダプタは邪魔だし、かといって、USB2つは二股みたいなケーブルで、場所によっては延長ケーブルを噛ましてつなぐということをしてました。

USB-C 対応が出た

USB-Cになると、電源を1つで取れるため、最高にスッキリしました。 また、ケーブルが絡まって外れちゃったりといったことがなく最高です。

Plugable USB 3.1 Gen 2 Type-C - SATA 変換ケーブル

Plugable USB 3.1 Gen 2 Type-C - SATA 変換ケーブル

USB-Cの恩恵を最大限に受け、スマートにSSDをストレージとして使えます。 今のところ自分の中でベストUSB-Cケーブルです