のぴぴのメモ

自分用のLinuxとかの技術メモ

VPCのsubnetのCIDRの割り当てのメモ

VPCのCIDRを"10.1.0.0/16"とした時のCIDR例。
私は検証用途での利用でIPが枯渇するほどインスタンスを起動するわけではなので、IPアドレス範囲をキツキツには設計していない。

  • ポイント
    • Privateサブネットは少し大きめの19bitで切る。
    • Publicサブネットは、10.1.0.0/19の範囲をさらに24bitで切って利用する
    • AZ間は間違えないように離れた番号を利用するようにアドレスを割り当てる

サブネットのCIDR割り当て例

#大区分小区分項目CIDRIPアドレス範囲
1PublicAZ-1PublicSubnet110.1.0.0/2410.1.0.1-10.1.0.254
2未使用10.1.1.0/24

10.1.15.0/24
10.1.1.1-10.1.15.254
3AZ-2PublicSubnet210.1.16.0/2410.1.16.1-10.1.16.254
4未使用10.1.17.0/24

10.1.31.0/24
10.1.0.1-10.1.7.254
5PrivateAZ-1PrivateSubnet110.1.32.0/1910.1.32.1-10.1.63.254
6未使用10.1.64.0/1910.1.64.1-10.1.95.254
7未使用10.1.96.0/1910.1.96.1-10.1.127.254
8AZ-2PrivateSubnet210.1.128.0/1910.1.128.1-10.1.159.254
9未使用10.1.160.0/1910.1.160.1-10.1.191.254
10未使用10.1.192.0/1910.1.192.1-10.1.223.254
11未使用未使用未使用10.1.224.0/1910.1.224.1-10.1.255.254

参考

"10.1.0.0/16"の範囲を19bitで分割した時のCIDR一覧

CIDRIP範囲IPアドレス(2進数)
Subnet11111111 11111111 11100000 00000000
10.1.0.0/1910.1.0.1 - 10.1.31.25400001010 00000001 00000000 00000000
10.1.32.0/1910.1.32.1 - 10.1.63.25400001010 00000001 00100000 00000000
10.1.64.0/1910.1.64.1 - 10.1.95.25400001010 00000001 01000000 00000000
10.1.96.0/1910.1.96.0 - 10.1.127.25500001010 00000001 01100000 00000000
10.1.128.0/1910.1.128.0 - 10.1.159.25500001010 00000001 10000000 00000000
10.1.160.0/1910.1.160.0 - 10.1.191.25500001010 00000001 10100000 00000000
10.1.192.0/1910.1.192.0 - 10.1.223.25500001010 00000001 11000000 00000000
10.1.224.0/1910.1.224.0 - 10.1.255.25500001010 00000001 11100000 00000000

AWS CloudFormation 起動テンプレート+CloudFormationヘルパースクリプトを使ってFowardProxyインスタンスを複数作成する

やりたいこと

CloudFormationでsquidのFowardProxyインスタンスをCloudFormationヘルパースクリプトを利用してインスタンス起動時にセットアップするようにしています。このインスタンスをAutoscalingは使用せず複数個作成したいと思い、EC2の起動テンプレートを組み合わせることで、効率良く起動するようにしています。

構成

f:id:nopipi:20190427234531p:plain
CloudFormation:起動テンプレートとCfnヘルパーの組み合わせで複数のProxyを作成する

ポイント

  • Cfnヘルパースクリプト用の定義を、EC2起動テンプレートのリソースのMetadataとして定義
  • Cfnヘルパースクリプトのオプション
    • 起動テンプレートのUserDataでcfn_initコマンドでcfnヘルパーを実行するようにする
    • その時Cloudformationの指定リソースを、”--resource ProxyLunchTemplate ”と起動テンプレートのリソースを指定する

CloudFormationテンプレート例

AWSTemplateFormatVersion: '2010-09-09'
Description: Outbound from the On-premises Environment
#----------------------------------------------
Parameters:
  Environment:
    Type: String
    Default: Dev
    AllowedPattern: "[a-zA-Z0-9=-@+?[?]?<?>._]*"
    ConstraintDescription: Can contain only ASCII characters.
  #------------------
  VpcId:
    Type: AWS::EC2::VPC::Id
  Subnet1Id:
    Type: AWS::EC2::Subnet::Id
    Description: Specify 1st Subnet to run Proxy instances.
  Subnet2Id:
    Type: AWS::EC2::Subnet::Id
    Description: Specify 2nd Subnet to run Proxy instances.
  #------------------
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: (required) Name of an existing EC2 key pair
  ProxyInstanceType: 
    Type: String 
    Default: m5.large 
    ConstraintDescription : Must be a valid EC2 instance type
    AllowedValues: 
      - t2.micro 
      - t2.small 
      - t2.medium 
      - t2.large 
      - t2.xlarge 
      - t2.2xlarge 
      - m5.large 
      - m5.xlarge 
      - m5.2xlarge 
      - m5.4xlarge 
      - m5.12xlarge 
      - m5.24xlarge 
  ProxyAmiId:
    Type: AWS::EC2::Image::Id
    Description: (required) AMI ID
    Default: ami-0f9ae750e8274075b  #for Tokyo-region
    #Default: ami-0b419c3a4b01d1859  #for singapore-region
  ProxyAutoRecoveryMinutes:
    Type: Number
    Description: Auto Recovery Time(Minutes)
    Default: 1
    MinValue: 1
    MaxValue: 120
  #------------------
Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      -
        Label:
          default: "General"
        Parameters:
          - Environment
      -
        Label:
          default: "Network"
        Parameters:
          - VpcId
          - Subnet1Id
          - Subnet2Id
      -
        Label:
          default: "Forward Proxy"
        Parameters:
          - KeyName
          - ProxyInstanceType
          - ProxyAmiId
          - ProxyAutoRecoveryMinutes
#----------------------------------------------
Resources:
  ProxySG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${Environment}-ProxySecurityGroup
      GroupDescription: Allow Proxy inbound access
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 3128
          ToPort: 3128
          CidrIp: 0.0.0.0/0
        -
          IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags: 
        - Key: Name
          Value: !Sub ${Environment}-ProxySecurityGroup
  #------------------
  ProxyLunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: FowardProxyLunchTemplate
      LaunchTemplateData:
        ImageId: !Ref ProxyAmiId
        InstanceType: !Ref ProxyInstanceType
        KeyName: !Ref KeyName
        SecurityGroupIds:
          - !Ref ProxySG
        Monitoring:
          Enabled: true
        TagSpecifications:
          -
            ResourceType: instance
            Tags:
              - Key: Name
                Value: !Sub ${Environment}-ProxyInstance
        UserData:
          Fn::Base64: !Sub | 
            #!/bin/bash -xe
            yum update -y 
            yum install -y aws-cfn-bootstrap cloud-init aws-cli 
            /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource ProxyLunchTemplate --region ${AWS::Region} --configsets proxy_setup
            /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ProxyLunchTemplate --region ${AWS::Region}
    Metadata:
      AWS::CloudFormation::Init: 
        configSets: 
          proxy_setup:
            - install_squid 
            - setup_squid 
        install_squid: 
          packages: 
            yum: 
              squid: [] 
        setup_squid: 
          files: 
            "/etc/squid/squid.conf": 
              content: !Sub | 
                # define ip address 
                acl localnet src 127.0.0.0/8 
                acl localnet src ::1/128 
 
                acl SSL_ports port 443 
                acl Safe_ports port 443
                acl CONNECT method CONNECT 
                http_access deny !Safe_ports 
 
                # Deny CONNECT to other than secure SSL ports 
                http_access deny CONNECT !SSL_ports 
 
                # Only allow cachemgr access from localhost 
                http_access allow localhost manager 
                http_access deny manager 
 
                # from where browsing should be allowed 
                http_access allow localnet 
 
                # include url white list 
                acl whitelist dstdomain "/etc/squid/whitelist" 
                http_access allow whitelist 
 
                # And finally deny all other access to this proxy 
                http_access deny all 
                #------------------------------------------ 
                http_port 3128

                # Leave coredumps in the first cache dir
                coredump_dir /var/spool/squid
 
                # anonymouse host name
                visible_hostname unknown
              mode: '000640'
              owner: root
              group: squid
            "/etc/squid/whitelist":
              content: !Sub |
                .google.co.jp
                github.com
                gist.github.com
              mode: '000640'
              owner: root
              group: squid
          services:
            sysvinit:
              squid:
                enabled: true
                ensureRunning: true
                files:
                  - "/etc/squid/squid.conf"
                  - "/etc/squid/whitelist.conf"
  #------------------
  ProxyInstance1: 
    Type: AWS::EC2::Instance 
    Properties:
      LaunchTemplate:
        LaunchTemplateName: FowardProxyLunchTemplate
        Version: !GetAtt ProxyLunchTemplate.LatestVersionNumber
      SubnetId: !Ref Subnet1Id
      SourceDestCheck: false
  ProxyInstance2: 
    Type: AWS::EC2::Instance 
    Properties:
      LaunchTemplate:
        LaunchTemplateName: FowardProxyLunchTemplate
        Version: !GetAtt ProxyLunchTemplate.LatestVersionNumber
      SubnetId: !Ref Subnet2Id
      SourceDestCheck: false
  #------------------
Outputs:
  ProxyInstance1PrivateIp:
    Description: 'Foward Proxy #1 Private IP'
    Value: !GetAtt ProxyInstance1.PrivateIp
    Export:
      Name: !Sub "${AWS::StackName}-ProxyInstance1PrivateIp"
  ProxyInstance2PrivateIp:
    Description: 'Foward Proxy #2 Private IP'
    Value: !GetAtt ProxyInstance2.PrivateIp
    Export:
      Name: !Sub "${AWS::StackName}-ProxyInstance2PrivateIp"

(AWS) UserDataとCloudFormationヘルパースクリプトの定義情報取得や実行契機の違い

定義箇所とインスタンス内からの定義情報取得方法の違い

UserDataはEC2インスタンスの機能で、CloudFormationヘルパースクリプトはCloudFormationの機能です。
UserDataはインスタンスメタデータ*1から情報を取得するため、実質VPC設定やIAMロールを考慮する必要がありません。一方CloudFormationヘルパースクリプトは、CloudFormationのパブリックにあるエンドポイントから取得するためInternet GatewayやCloudFormationのVPC Endpointを用意してパブリックのエンドポイントにアクセスできるようにする必要があります。

機能 機能を提供しているサービス 定義 インスタンスからの取得方法 通信要件
UserData EC2 EC2インスタンス起動オプション インスタンスメタデータから取得 不要
Cfnヘルパー CloudFormation CloudFormationのテンプレート(ResourceのMetadata定義) CloudFormationのエンドポイントから取得 IGW経由またはVPCEndpoint経由でCloudFormationのパブリックエンドポイントにアクセス可能なこと

絵に描くとこんな感じでしょうか。(逆に判りずらいかも)

f:id:nopipi:20190427235711p:plain

実行モジュールと実行契機の違い

AWSが提供するAMIを利用した場合UserDataは、cloud-initというツールの中で実行されておりOS起動時に自動実行されます。一方CloudFormationヘルパースクリプトは自動実行されないため明示的に実行する必要があり、通常はUserDataにコマンドを記載して、UserDataから実行させます。

機能 パッケージ 起動契機 インスタンス無いでの設定ファイル
UserData cloud-init*2 OS起動時に自動実行(systemdからキックされる) /etc/cloud/配下
Cfnヘルパー aws-cfn-bootstrap*3 明示的に実行(UserDataに実行コマンドを埋め込む) なし(CfnのスタックのMetadataに定義)

VSCodeでAWS CloudFormation(YAML)を作成する環境を整備する

VSCodeAWS CloudFormationをYAMLで作成する環境の設定手順です。

やること

  1. VSCodeのセットアップ
  2. YAMLの構文チェック用にエクステンション"YAML Language Support by Red Hat"をVSCodeに追加
  3. CloudFormationの構文チェック用のカスタム設定をVSCode設定に追加

VSCodeのセットアップ

MacへのVSCodeインストール(とgit連携)はこちらを参照
nopipi.hatenablog.com

YAMLエクステンションの追加

VSCoderedhatYAMLエクステンションを追加します。ここではCUIGUIの両方の手順を記載します。

CUIでインストールする場合

下記コマンドでYAMLエクステンションを追加します。

code --install-extension redhat.vscode-yaml

GUIでインストールする場合

  1. 左のバーから"Extentions"をクリック
  2. 検索ボックスでYAMLでエクステンションを検索し、"YAML Language Support by Red Hat"を選択
  3. "Install"でエクステンションを追加する

(1)左バーからExtentionボタンをクリックし、(2)キーワードYAMLで検索、(3)redhat YAMLをインストール
GUI操作でのYAMLエクステンションインストール

CloudFormationの構文チェック用のカスタム設定追加

下記設置を追加します

  1. CloudFormation仕様の追加
  2. CloudFormationのカスタムタグ定義の追加

設定(1) CloudFormation仕様の追加

VSCodeの設定ファイル(Macの場合: $HOME/Library/Application Support/Code/User/settings.json)*1に、CloudFormationのリソース仕様を追加します。この設定でをすると、拡張子がcf.yamlのファイル、cfn/、cloudformation配下のYAMLファイルがCloudFormation用のYAMLとして指定したソース仕様にしたがってチェックされます。

  1. コマンドパレット(⇧⌘P)を開いて >settings (JSON) と打ち込みsettings.jsonを開く。
  2. 下記定義を追加する
    "yaml.schemas": {
        "https://d33vqc0rt9ld30.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json": [
            "*.cf.yaml",
            "*.cf.yml",
            "cfn/*.yaml",
            "cfn/*.yml",
            "cloudformation/*.yaml",
            "cloudformation/*.yml"
        ]
    },

設定(2) CloudFormationのカスタムタグ定義の追加

デフォルトのままだと!Sub, !RefなどのCloudFormation固有のスキーマYAMLの構文エラーとなるため、これら固有スキーマを追加します。内容はこちらのIssueAndyJPhillipsさんのコメント内容を流用しています。

    "yaml.customTags": [
        "!And sequence",
        "!Equals sequence",
        "!If sequence",
        "!Not sequence",
        "!Or sequence",
        "!Base64",
        "!Cidr sequence",
        "!FindInMap sequence",
        "!GetAtt",
        "!GetAZs",
        "!ImportValue",
        "!Join sequence",
        "!Select sequence",
        "!Split sequence",
        "!Sub",
        "!Ref"
    ]

(参考)setting.json全体の内容

設定(1)&(2)をすると、既存の設定に、下記設定が追加された形になります。

{
    <既存の設定>
    "yaml.schemas": {
        "https://d33vqc0rt9ld30.cloudfront.net/latest/gzip/CloudFormationResourceSpecification.json": [
            "*.cf.yaml",
            "*.cf.yml",
            "cfn/*.yaml",
            "cfn/*.yml",
            "cloudformation/*.yaml",
            "cloudformation/*.yml"
        ]
    },
    "yaml.customTags": [
        "!And sequence",
        "!Equals sequence",
        "!If sequence",
        "!Not sequence",
        "!Or sequence",
        "!Base64",
        "!Cidr sequence",
        "!FindInMap sequence",
        "!GetAtt",
        "!GetAZs",
        "!ImportValue",
        "!Join sequence",
        "!Select sequence",
        "!Split sequence",
        "!Sub",
        "!Ref"
    ]
}

mac版PowerPoint消えなくなった自動回復ファイルを手動削除する手順

Mac版のPowerPointを利用していて、PowerPointを起動するたびに古い自動回復ファイルが開いて対処するのが面倒でした。なんとか古い自動回復ファイルを消せないかなと調べた内容を備忘録で残します。

手順

MacPowerPointの自動回復ファイルの保存先フォルダパス

~/Library/Containers/com.microsoft.Word/Data/Library/Preferences/AutoRecovery/

削除手順

  • (1)PowerPointを停止して
  • (2)コンソールを開いて下記コマンドで自動回復ファイルを削除する
cd ~/Library/Containers/com.microsoft.Word/Data/Library/Preferences/AutoRecovery/
rm -i *

Amazon RDSのIOPS&容量変更をCLIで実行するサンプル

RDS プロビジョンド IOPSで、IOPSを変更して、DBがAvailableになるまでWaitするシェル(+AWS CLI)のサンプルです。
AWS CLIで”aws rds modify-db-instance”で変更をします。
RDS&プロビジョンド IOPSで、IOPS設定によるBLOBファイルインサートのパフォーマンスの影響を確認するための検証ツール作成に利用したものです。

コマンド

DBIdentifier="dbname"
RDS_SIZE=1024  #1TB
RDS_IOPS=4096

#Modify RDS storage(size and iops)
echo "$(date '+%Y/%m/%d %H:%M:%S'): Modify RDS storage"
aws rds modify-db-instance \
        --db-instance-identifier ${DBIdentifier} \
        --allocated-storage ${RDS_SIZE} \
        --iops ${RDS_IOPS} \
        --apply-immediately;

# Wait until the DBInstanceStatus is "Available"
sleep 30
while true
do
     STAT=$(aws --output text rds describe-db-instances \
          --db-instance-identifier ${DBIdentifier} \
          --query 'DBInstances[].DBInstanceStatus')
     if [ "A${STAT}" == "Aavailable" ]; then
          break
     else
          echo "$(date '+%Y/%m/%d %H:%M:%S'): DBInstanceStatus= ${STAT}"
          sleep 15
     fi
     done
echo "$(date '+%Y/%m/%d %H:%M:%S'): Done to modifying RDS"

注意事項

  • ストレージの設定変更後、6時間はストレージの再変更ができません。実行すると以下のような感じのエラーが出ます。
An error occurred (InvalidParameterCombination) when calling the ModifyDBInstance operation: You can't currently modify the storage of this DB instance. Try again after approximately 3 hours.

CloudTrailの「組織の証跡」でOrganizationsメンバアカウントに一括CloudTrailを設定する手順 (ロギング専用アカウント+KMS暗号化)

はじめに

AWS Oraganizationsを利用したマルチアカウント構成で、Oraganizationsの配下のAWSアカウントに共通のCloudTrail設定を行うことができる「組織の証跡」が CloudTrailにあります。ドキュメントは以下になりますが、logging専用のAWSアカウントのS3バケットを利用してかつKMSによる暗号化と組み合わせたやり方の情報がなかったので試行錯誤の結果をまとめました。
docs.aws.amazon.com

構成の説明

f:id:nopipi:20190308003130p:plain
組織の証跡の設定概要

  • 設定のポイント
    • CloudTrailのログは、ロギングアカウントのS3バケットに保存します。
    • またS3保管時にKMSによる暗号化を行います。
    • KMSの鍵はロギングアカウントで管理します。
  • アカウントとOrganizations構成
    • マスターアカウント:111111111111
    • リリースアカウント:222222222222
    • ロギングアカウント:333333333333
    • OrganizationsのID: o-yyyyyyyyyy
  • S3バケットとKMSか
  • 設定時の権限
    • 今回は、AdministratorAccessポリシーが付与されている環境で作業しています

設定手順

ロギングアカウント(S3とKMSの作成)

S3バケットの準備

S3バケットを作成します。CloudTrail設定で最も重要なバケットポリシーには、以下の設定を行います。

  • 1つめ: CloudTrailサービスからのバケットACL変更を許可する
  • 2つめ:マスターアカウントの証跡書き込みを許可する
  • 3つめ: 「組織の証跡」を許可する
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSCloudTrailAclCheck20150319",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:GetBucketAcl",
            "Resource": "arn:aws:s3:::trailbucket"
        },
        {
            "Sid": "AWSCloudTrailWrite20150319",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::trailbucket/AWSLogs/111111111111/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        },
        {
            "Sid": "AWSCloudTrailWrite20150319",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::trailbucket/AWSLogs/o-yyyyyyyyyy/*",
            "Condition": {
                "StringEquals": {
                    "s3:x-amz-acl": "bucket-owner-full-control"
                }
            }
        }
    ]
}

ドキュメントでは設定は以下に説明があります。
docs.aws.amazon.com

KMSの準備

CloudTrailがS3にPUTするときの暗号化に利用するKMSのカスタマーマスターキー(CMK) を作成します。
カスタマーポリシーは、今回はCloudTrailの書き込みに必要な最低限のポリシーを付与しています。

{
    "Version": "2012-10-17",
    "Id": "Key policy created by CloudTrail",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:sts::333333333333:assumed-role/OrganizationAccountAccessRole/admin",
                    "arn:aws:iam::333333333333:root"
                ]
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow CloudTrail to encrypt logs",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "kms:GenerateDataKey*",
            "Resource": "*",
            "Condition": {
                "StringLike": {
                    "kms:EncryptionContext:aws:cloudtrail:arn": "arn:aws:cloudtrail:*:111111111111:trail/*"
                }
            }
        },
        {
            "Sid": "Allow CloudTrail to describe key",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudtrail.amazonaws.com"
            },
            "Action": "kms:DescribeKey",
            "Resource": "*"
        }
    ]
}

マスターアカウント(CloudTrailの設定)

マスターアカウントのCloudTrailに移動し、「監査情報」から「証跡の作成」を実行します。

  • ポイント
    • 「組織に証跡を適用」を「はい」とすると、「組織の証跡」が作成されます
    • 「証跡情報を全てのリージョンに適用」を「はい」にして全リージョンに設定を適用します

f:id:nopipi:20190308010258p:plain:w550

  • 出力先S3バケット設定
    • バケット名:「新しいバケットを作成する」を「いいえ」にし、バケット名を入力する
    • KMS暗号化
      • 「SSE-KMS を使用してログファイルを暗号化」を「はい」にし、
      • 「新規の KMS キーの作成」を「いいえ」にして、
      • ロギングアカウントで作成したCMKのARNを入力する

f:id:nopipi:20190308011020p:plain:w550

  • メモ
    • 作成した証跡はメンバーアカウントでは削除できません
    • マスターアカウントで証跡を削除するとメンバーアカウントの証跡も削除されます
    • 証跡作成時に、S3バケットポリシーの権限が不足していてもマネコン上では「KMSの権限不足」と表示されるようです(私はそれでハマりました)

完了

作成に成功してしばらく経つと、各メンバーアカウント状に同じ設定のCloudTrail設定が作成されます。
今回の例の場合、指定したS3バケットには以下のような構成でCloudTrailのログが出力されます。

trailbucket
└ AWSLogs
  ├ 111111111111
  │ ├ CloudTrail-Digest
  │ └ CloudTrail
  └ o-yyyyyyyyyy
    ├ 111111111111
    │ ├ CloudTrail-Digest
    │ └ CloudTrail
    ├ 222222222222
    │ ├ CloudTrail-Digest
    │ └ CloudTrail
    └ 333333333333
      ├ CloudTrail-Digest
      └ CloudTrail

Lambdaの実行ロールのクレデンシャルを確認してみた

はじめに

Lambdaの関数からAWS APIを実行する場合、Lambdaに付与した実行ロール(Execution role)の権限が利用されます。
docs.aws.amazon.com
というところまではすぐにわかったのですが、この実行ロールのクレデンシャルをLambda上でどう取得しているかがパッとわからなかったので、実機で確認しました。確認はPythonで実施しています。

結論

結論を述べると、Lambdaを実行する環境の「環境変数」から実行ロールのクレデンシャルを取得することができます。

Lambda検証コード(python)

import os
import json
import boto3

def lambda_handler(event, context):
    
    print('AWS_ACCESS_KEY_ID={}'.format(os.environ['AWS_ACCESS_KEY_ID']))
    print('AWS_SECRET_ACCESS_KEY={}'.format(os.environ['AWS_SECRET_ACCESS_KEY']))
    print('AWS_SESSION_TOKEN={}'.format(os.environ['AWS_SESSION_TOKEN']))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

検証コードの実行結果

START RequestId: 6b84d91a-2cb7-49ec-83d1-0844247f2188 Version: $LATEST
AWS_ACCESS_KEY_ID=ASIAT5XxxxxxxxxxxS4G
AWS_SECRET_ACCESS_KEY=UJ7JT9M7kxxxxxxxxxxxxxxxxxRbujmy7DwdyrK+
AWS_SESSION_TOKEN=FQoGZXIvYXdzEEcaFlCTJtylI<中略>IBTtPdOoott/04wU=
END RequestId: 1b54a3fa-4793-XXXX-XXXX-e6a1f102c0ef
REPORT RequestId: 1b54a3fa-4793-XXXX-XXXX-e6a1f102c0ef	Duration: 124.07 ms	Billed Duration: 200 ms 	Memory Size: 128 MB	Max Memory Used: 76 MB

クレデンシャルはマスクしています。
ドキュメントを確認すると、Lambdaの環境変数一覧にクレデンシャルがありました。
docs.aws.amazon.com

調査履歴

Lambdaの実行ロールを利用したAWS API実行

Lambda上でAWS APIを実行する場合は通常、EC2やオンプレ環境と同様にAWS SDKを利用してAPIを実行します。例えばS3のバケット一覧取得をLambda上でpythonで実行する場合は、以下のようなコードを書きます。

import json
import boto3

def lambda_handler(event, context):
    
    s3 = boto3.resource('s3')
    for bucket in s3.buckets.all():
        print('{}'.format(bucket.name))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

このコード例を見ると、Lambda固有の書き方をする部分もありますが、AWS APIを実行するためのセッション取得の部分は” s3 = boto3.resource('s3')”とオンプレやEC2から実行する場合と変わらないです。またAWS SDKもLambda専用のSDKという記載はドキュメントには(私が調べた限り)ありませんでした。

ということから、セッション取得のためのクレデンシャル情報の取得はオンプレやEC2インスタンスと同様の挙動で取得しているのではないかということが考えられます。

AWS SDK(boto3)におけるクレデンシャル情報の取得

次にAWS SDKがどのようにクレデンシャル情報を取得しているかということを、ここでおさらいします。
boto3のクレデンシャルの取得手順は、公式ドキュメントでは下記に記載があります。

こちらの内容によると、boto3でのクレデンシャル取得は、以下の優先順で取得するとあります。

  1. boto.client() 実行時に、パラメータとしてクレデンシャル情報を明示的に引き渡す
  2. セッションオブジェクト作成時に、パラメータとしてクレデンシャル情報を明示的に引き渡す
  3. 環境変数
  4. AWS config file (~/.aws/config)
  5. Assume Role provider
  6. Boto2のconfigファイル(/etc/boto.cfg and ~/.boto)
  7. EC2インスタンスロール(EC2メタデータ: http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名称)

クレデンシャル情報取得方法の絞り込み

上記のboto3のクレデンシャル情報取得方法の優先順位とLambdaのサンプルコードからLambdaの実行ロールのクレデンシャル取得で可能性のない方式を除外します。

  • boto.client()実行時にコード上でクレデンシャル情報を明示的にしていない・・・該当しない(コードでクレデンシャルの指定なし)
  • セッションオブジェクト作成時にクレデンシャル情報を指定する ・・・・・・該当しない(セッション取得の関数は利用していない)
  • Assume Role provid・・・該当しない(コード上に該当する箇所がない。また後述するがconfigに該当箇所がない)

絞り込んで残った候補は以下の4つです。

  1. 環境変数
  2. AWS config file (~/.aws/config)
  3. Boto2のconfigファイル(/etc/boto.cfg and ~/.boto)
  4. EC2インスタンスロール(EC2メタデータ: http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名称)

configtと boto.cfgの確認 > なし

雑なコードですが下記コードでconfig, boto.cfg, .botoファイルの有無を確認します。(file=のファイル名にそれぞれのファイルのパスを設定して実行)
結果として、3つのファイルとも存在していないことが確認できました。

import json
import boto3

def lambda_handler(event, context):

    file='~/.aws/config'
    fp = open(file, "r")
    for line in fp:
        print('{}'.format(line))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

EC2インスタンスロールの確認

EC2インスタンスロールと同様にインスタンスメタデータ(http://169.254.169.254/latest/meta-data)から取得できるか確認します。

検証コード

この検証コードではLambdaが実行されているインスタンスの、インスタンスメターデータの取得を試みています。

import urllib.request
import json
import boto3

def lambda_handler(event, context):
    
    url = 'http://169.254.169.254/latest/meta-data/'
    
    try:
        req = urllib.request.Request(url)
        with urllib.request.urlopen(req) as res:
            print(res.read())
    except urllib.error.URLError as e:
        print(e.reason)
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
結果 > 取得失敗

実行の結果、”Connection refused”とエラー応答があり、メタデータである'http://169.254.169.254’からクレデンシャル取得を行うことは出来ませんでした。

START RequestId: df6064d2-ee6e-4c73-9dd5-d99f44de5ea3 Version: $LATEST
[Errno 111] Connection refused
END RequestId: df6064d2-ee6e-4c73-9dd5-d99f44de5ea3
REPORT RequestId: df6064d2-ee6e-4c73-9dd5-d99f44de5ea3  Duration: 1057.08 ms	Billed Duration: 1100 ms 	Memory Size: 128 MB	Max Memory Used: 77 MB	

環境変数の確認

下記環境を準備し、Lambdaの実行環境の環境変数を確認します。

import os
import json
import boto3

def lambda_handler(event, context):
    for key in os.environ:
        print('{:30s}= {}'.format(key, os.environ[key]))
    
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

確認すると、Lambdaの実行環境内にAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、下記のクレデンシャルコードが存在していることがわかりました。

Amazon SNSからプッシュ通知をPublishする時のメモ

モバイルプッシュ関連のblog記事

マネージメントコンソールからJSON形式でメッセージを送る例

{
"APNS_SANDBOX":"{\"aps\": {\"alert\": {\"title\":\"テスト\",\"body\":\"これはテストメッセージです\"}, \"sound\": \"default\", \"badge\":1}}"
}

こちらを参考
qiita.com

Python+SDK(boto3)でPublishする例

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

import sys
import json
import boto3

PLATFORM   = 'APNS_SANDBOX'
TARGET_ARN = u'arn:aws:sns:ap-northeast-1:270025184181:endpoint/APNS_SANDBOX/SNSTestAPNs/b93b1ab2-4be5-3db1-bfd6-af6d5adb62c7'


def main():

    dict = {
             'aps': {
               'alert': {
                 'title': 'テスト',
                 'body':  'これはテストメッセージです'
               },
               'sound': 'default',
               'badge': 1
               }
           }
    message = {PLATFORM: json.dumps(dict)}
    messageJSON = json.dumps(message)

    # Get session
    client = boto3.client('sns')

    request = {
        'TargetArn': TARGET_ARN,
        'Message': messageJSON,
        'MessageStructure': 'json'
    }
    response = client.publish(**request)

if __name__ == "__main__":
    sys.exit(main())

Amazon SNSとiOSでモバイルプッシュを試してみる

検証環境のモバイルプッシュ通知の流れ

Appleのプッシュ通知サービス

Apple製品のプッシュ通知は、Apple Push Notification Service(APNs)と呼ばるAppleが提供するプッシュ通知サービスを利用して各デバイスにプッシュ通知を送ります。*1

プッシュ通知をする時は、Provider(要はサーバ)からAPNsに要求を送り、要求を受けたAPNsが指定されたデバイスにプッシュ通知を送付します。ProviderからAPNsへの要求では、通知先のデバイスの情報(デバイストークンという、デバイス+アプリの組み合わせで一意に生成されるトークン)とプッシュ通知の内容を送ります。

f:id:nopipi:20190216233223p:plain:w400

Amazon SNSモバイルプッシュとは

Amazon Simple Notification Service(SNS)の機能の一つで、様々な種類のモバイルデバイスのアプリケーションにプッシュ通知メッセージを送付するための抽象化されたサービスです。*2

先ほどのAppleのプッシュ通知の概要図のProvider部分を担うサービスになります。

f:id:nopipi:20190216234056p:plain:w400

プッシュ通知の流れ

プッシュ通知は大きく、(1)デバイストークンの取得と、(2)プッシュ通知の実行、に区分されます。ここではこの記事で作成する検証環境でのプッシュ通知の流れを説明します。

f:id:nopipi:20190206042218p:plain:w500

  1. バイストークンの取得(下図の緑吹き出し)
    1. iOSで検証用アプリケーションでAPNsからデバイストークンを取得
      1. バイストークンは、デバイスとアプリの組み合わせで一意に生成されるトークンです
      2. バイストークンはAppleのドキュメントでは、アプリ起動毎に取得することが推奨されてます*3
    2. 取得したデバイストークンをSNSに登録
  2. プッシュ通知(下図のオレンジ吹き出し)
    1. アプリケーションからSNSに通知の実行を指示(publish)
    2. SNSは、APNsにプッシュ要求を送付
    3. 要求を受けたAPNsは、指定されたデバイスにプッシュを通知

開発環境

この記事でのアプリケーション開発環境は以下の通りです

  • 開発言語: Swift(Swift4.2)
  • Xcode: Version 10.1 (10B61)
  • OS: macOS Mojave 10.14.3

クライアントアプリケーションの開発と実行

APNs設定

クライアントアプリケーションの開発前に、APNsへの設定が必要になります(APNsへの登録には、Apple Developer Programへの登録(有償)が必要です)。下記の記事を参考にAPNsの設定を行い、開発用プロビショニングプロファイルと、NotificationsのSSL証明書作成と登録、を準備してください。
nopipi.hatenablog.com

簡易クライアントアプリ作成

ここでは、プッシュ通知に必要となるDeviceTokenをAPNsから取得するのみの簡易的なアプリを作成します。

取得したDeviceTokenは、この検証環境ではXcodeのデバイスコンソールにログ出力させた上で手動でSNSに登録させます。(本来はサーバを立ててそのサーバに通知させてSNS登録させます)

Xcodeでプロジェクトを作成しセッティングする

まずはXcodeでSwift開発のプロジェクトを作成して、必要なセッティングをします。

  • (1) プロジェクトの作成
    • Xcodeを起動し"Create a new Xcode project"を選択します。

f:id:nopipi:20190216191753p:plain:w450

  • (2) テンプレートの選択
    • シンプルな”Single View App”を選択します。

f:id:nopipi:20190216191806p:plain:w450

  • (3) プロジェクトの設定
    • プロジェクトの設定を行います。注意しなければならないのは、以下の3点です。
      • Organization Name: APNs登録で作成した「iOSアプリ開発用証明書」を選択
      • Organization Identifier: APNs登録で作成したApp IDの「Bundle ID」を指定する(異なる指定を指定するとBuildでエラーになる)
      • Language: Swiftを選択

f:id:nopipi:20190216220918p:plain:w450

  • (4) 開発用プロビショニングプロファイルの設定
    • ProjectNavigator(左のバー)のトップ(図のSnsTest部分)をクリック
    • 「General」タブを選択
    • 「Automatically manage signing」無効化する
    • 下記2箇所に事前に作成した開発用プロビショニングプロファイルを指定します。
      • Signing(debug)
      • Signing(Release)
    • プロビジョニングファイルは、事前にダウンロードしたもののインポートと、XcodeがDeveloperからダウンロードする、のいずれかの方法で設定します。

f:id:nopipi:20190217002555p:plain:w450

  • (5) Notificationの有効化
  • プロジェクトのターゲット設定画面のタグで「Capabilities」を選択
  • 「Push Notifications」をONにする

f:id:nopipi:20190217002612p:plain:w450]

Device Token取得コードの追加

アプリケーション起動時にデバイストークンを取得するコードを追加します。

  • 「AppDelegate.swift」を開く
  • 下記の図の部分に、デバイストークン取得とコンソールへのデバイストークン出力用のコードを追加します。

f:id:nopipi:20190217011255p:plain

//
//  AppDelegate.swift
//  SnsTest
//
//  Created by NF on 2019/02/16.
//  Copyright © 2019 NopipiDevTeam. All rights reserved.
//

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        // デバイストークンの要求
        if #available(iOS 10.0, *){
            /** iOS10以上 **/
            let center = UNUserNotificationCenter.current()
            center.requestAuthorization(options: [.alert, .badge, .sound]) {granted, error in
                if error != nil {
                    // エラー時の処理
                    return
                }
                if granted {
                    // デバイストークンの要求
                    print("Get a device token.")
                    UIApplication.shared.registerForRemoteNotifications()
                    print("Done to get a device token.")
                }
            }
        } else {
            /** iOS8以上iOS10未満 **/
            //通知のタイプを設定したsettingを用意
            let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            //通知のタイプを設定
            application.registerUserNotificationSettings(setting)
            //DevoceTokenを要求
            application.registerForRemoteNotifications()
        }
        
        return true
    }

    // デバイストークン取得が成功した場合呼び出される関数
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
        print("DeviceToken: " + token)
    }

    // デバイストークン取得が失敗した場合呼び出される関数
    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
        // Try again later.
        print("Can not get Device token")
    }

   以下略
  • バイストークン取得で重要なコードは以下の部分です
    • "import UserNotifications" ・・・UserNotificationsライブラリのインポート
    • UIApplication.shared.registerForRemoteNotifications() ・・デバイストークン取得を実行するメソッド
    • func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) ・・・デバイストークン取得が成功した場合に良い出される関数
      • let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined() ・・・デバイストークン情報を16進数の文字列に変換する
      • print("Done to get a device token.")のコンソール出力

アプリケーションの実行とデバイストークン確認

  • (1) 実行用デバイス(iPhone)の準備
    • テストに利用するiPhoneXcodeを動かしているMacにUSB接続します
    • iPhoneの画面ロックがかかっている状態の場合はロック解除します
    • 右上の停止ボタン右側をクリックします
    • ”No devices connected to 'My Mac'を選択し、_UBS接続したデバイスを登録&選択します(既にデバイスが表示されている場合はそれを選択)
    • USB接続したデバイスをアプリケーションの実行環境として選択します

f:id:nopipi:20190217014514p:plain:w400

  • (2)Active Consoleの表示
    • 「View」->「Debug Area」->「Active Console」で)Active Consoleを開きます(Shift+Command+Cでも可)

f:id:nopipi:20190217014708p:plain:w400

  • (3)アプリケーションの実行
    • 左上の再生ボタンを押してアプリケーションを実行します
    • バイストークン取得が成功すると右下のコンソールにデバイス情報が出力されます

f:id:nopipi:20190217015729p:plain:w500

Amazon SNSへの登録とプッシュ通知の実行

Amazon SNSのアプリケーションプラットホーム作成

  • マネージメントコンソールにログインし、Amazon SNSの画面に移動します
  • 左のナビゲーションバーから「アプリケーション」を選択し
  • 「プラットホームアプリケーショの作成」を選択
  • 必要な情報を入力します
    • アプリケーション名:わかりやすい名称を指定
    • プッシュ通知プラットホーム:今回はAPNsのDevelopmentなので「Apple Development」を選択
    • プッシュ証明書タイプ:「iOSプッシュ証明書」を選択
    • P12ファイル:
      • ファイル選択こちらの最後で作成した、APNs用個人情報交換ファイル(.p12) を指定(ファイル名が日本語だとエラーになるようです)
      • パスワードの入力:P12ファイル生成時に指定したパスワードを指定します
      • 「認証情報」をファイルから読み込みを実行し、証明書・プライベートキーに表示されることを確認

f:id:nopipi:20190217020649p:plain:w500

バイストークン情報の登録

  • (1)プラットフォームエンドポイントの作成
    • 作成したアプリケーションプラットホームに移動し、「プラットフォームエンドポイントの作成」をクリックする
    • アプリケーションで取得したデバイストークンを登録する
    • 「エンドポイントの追加」をする

f:id:nopipi:20190217021508p:plain:w500

  • (2)プッシュ通知の実行
  • アプリケーションプラットフォームで、送信したいデバイスを選択します

f:id:nopipi:20190217023437p:plain:w500

f:id:nopipi:20190217023452p:plain:w500

  • ペイローの内容は以下の通りです。
{
"APNS_SANDBOX":"{\"aps\": {\"alert\": {\"title\":\"テスト\",\"body\":\"これはテストメッセージです\"}, \"sound\": \"default\", \"badge\":1}}"
}
  • こんな感じに送れます。

f:id:nopipi:20190217023907p:plain:w300

プッシュ通知のペイロードの詳細についてはこちらを参照
nopipi.hatenablog.com

macOSにAWS CLI(Ver.1)をセットアップする手順

MacAWS CLI(Version 1)をセットアップした時のメモです。python3ベースです。

macOS環境

  • macOSバージョン:macOS High Sierra Version 10.13.16
  • OS標準のpython: python2.7 -> なので個別にpython3をインストール

セットアップ手順

python3のインストール

下記リンク先から、python3のMacOSインストーラをダウンロードして、pythonをインストールする
今回は、Python/3.8.0a1をインストール

pipのセットアップ

curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py --user

aws cliのインストール

pip3 install awscli --upgrade --user

python3モジュールの実行パスの追加

echo 'PATH=${PATH}:/Users/nobuyuf/Library/Python/3.8/bin' >> ~/.bash_profile
echo 'export PATH' >> ~/.bash_profile

動作確認

$ aws --version
aws-cli/1.16.103 Python/3.8.0a1 Darwin/17.7.0 botocore/1.12.93

AWS Secrets ManagerをVPC閉域空間で利用するメモ

はじめに

AWS Secrets Managerとは

DBMSアクセスなどで利用するユーザ/パスワードを、アプリケーションのコードに埋め込むとか、APサーバに設定ファイルとしてで腹持ちさせて参照させるとか、セキュリティ的に良くないですがやってしまいがちだと思います。

AWS Secrets Manager はそのような、ユーザ/パスワードなどのシークレット情報を、所有する暗号化キーで暗号化し、AWS Key Management Service (KMS) に保管するサービスです。保管しているシークレート情報は、必要都度に取得して利用します。取得はIAMのきめ細かいポリシーを使用して制限できます。

ここではAWS Secrets ManagerをVPC閉塞空間で利用するための設定し、かつリソースポリシーでシークレット情報を取得可能なVPCを制限する手順を説明します。

  • 特徴*1
    • シークレットのセキュアなストレージ
    • アプリケーションに影響を与えずにシークレットを自動更新(Lambdaを利用(VPC内のLambdaも可能))
    • プログラムでのシークレットの取得
    • シークレットの使用状況の監査と監視
  • 料金: シークレット 1 件あたり 0.40 USD/月、10,000 回の API コールあたり 0.05 USD(2019/2現在)*2

ここでは説明しないこと

このページでは、下記については言及していません。必要に応じて他の情報源を参照して下さい。

  • ネットワーク(VPC、subnet、routeなど)
  • EC2インスタンスの作成(検証用EC2とFowardProxyのセットアップ)
  • RDS Auroraのセットアップ

アーキテクチャ

この手順で作成するSecretsManagerのアーキテクチャ図を示します。

f:id:nopipi:20190212224922p:plain

  • 対象VPC CIDR 10.11.0.0/16

設定手順(SecretsManagerからの情報取得)

SecretsManager用のKMSの鍵作成

SecretsManagerのデフォルトの鍵で暗号化することもできますが、ここでは独自作成したKMSの鍵で暗号化することとし、事前にKMSの鍵を作成します。

  • サービスからKMSのサービス画面に移動する

f:id:nopipi:20190212200743p:plain:w400

  • KMS鍵の名称を入力します

f:id:nopipi:20190212201109p:plain:w400

  • 「タグの追加」はスキップ
  • キーポリシー設定
    • キー管理者の設定:このキーを作成しているユーザのロールを指定します
    • キーの使用アクセス許可: 一旦未指定のままにします(後で作成する、SecretsManagerでシークレット情報を取得するロールを指定します)

新しいシークレットの作成

  • (1)「新しいシークレットの作成」をクリック

f:id:nopipi:20190212195728p:plain:w300

  • (2)シークレットの設定
    • シークレットタイプの選択
      • タイプ: ここでは「RDS データベース認証情報」を選択します
      • 対象DBユーザ: 管理したいDBユーザの、ユーザ名とパスワードを入力します。
      • 暗号化キーを選択: 作成したKMSの鍵を選択します
      • RDS データベースを選択: 対象のRDSを選択します。

f:id:nopipi:20190212210626p:plain:w400

  • (3)新しいシークレットの保存
    • シークレット名称を指定します
  • (4)自動ローテーションの設定
    • 一旦スキップします
  • (5)新しいシークレットの保存
    • 設定したシークレットキーを保存します。

VPC PrivateLinkの作成

Private Link用のセキュリティグループを作成する

対象VPC内からのアクセスを許可するように、対象VPCのCIDRに対してInbound許可を与えます。

タイプ プロトコル ポート範囲 ソース
HTTPS TCP 443 10.11.0.0/16
  • より厳密に設定する場合は、下記2箇所からのHttpsのInboundアクセスを許可させます。その場合、それぞれのSecurity Groupを作成し、そのSecurity Groupをhttpsのインバウンどのソースとして指定するのが効率的で良いです。
    • APサーバ(DBアクセスに必要なユーザ/パスワードのSecretsManagerから取得する)
    • VPC内のLambda(後述するローテーションで利用)
Secrets Manager用のVPC PrivateLinkの作成
  • エンドポイントのサービス名: com.amazonaws.ap-northeast-1.secretsmanager
  • VPCとSubnet: 対象のVPCとSubnetを選択します。今回は、PrivateSubnet1とPrivateSubnet2を選択します。
  • プライベート DNS 名を有効にする: このエンドポイントで有効にする(デフォルト設定のまま)
  • 上記で作成したPrivate Link用のセキュリティグループを選択します。

EC2インスタンスロール

APサーバからSecretsManagerのシークレット情報を取得するためのロールを作成します。ロールにはSecretsManagerからの情報取得のポリシーと、KMSからの鍵取得のポリシーを設定します。
EC2インスタンスから、SecretsManagerからパスワードを取得するIAMロールを作成して、EC2インスタンスにアタッチします。

インラインポリシー*3

下記の2つのポリシーを指定します(ARNは適時修正してください)。

  • (1) SecretsManagerからシークレット情報を取得するためのインラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret",
                "secretsmanager:ListSecrets"
            ],
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp"
        }
    ]
}
  • (2) KMSから鍵を取得するためのインラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:DescribeKey"
            ],
            "Resource": "arn:aws:kms:ap-northeast-1:445629031529:key/df0849ea-0c1a-44e3-b86b-43ae43396384"
        }
    ]
}
信頼関係ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
作成ロールのSecretsManager用KMS鍵のキーユーザへの登録

作成したEC2インスタンスロールを利用し、KMSのキーを取得できるように、KMS鍵のキーユーザに作成したロールを追加します。

  • KMSのサービス画面から「カスタマー管理型のキー」を選択し利用する鍵をクリックする
  • 「キーユーザー」に作成したロールを追加する

f:id:nopipi:20190212213205p:plain:w400

APサーバ上のAWS CLI設定

AWS CLIにProxy設定をしている場合、Proxyの除外設定にSecretsManagerのエンドポイントのURL(東京リージョンの場合”secretsmanager.ap-northeast-1.amazonaws.com”)を追加します。追加した後は再ログインして環境変数が反映されていることを確認します。

export HTTPS_PROXY=http://10.1.173.17:3128
export HTTP_PROXY=http://10.1.173.17:3128
export NO_PROXY=169.254.169.254,s3.ap-northeast-1.amazonaws.comi,secretsmanager.ap-northeast-1.amazonaws.com

APサーバでのシークレット情報取得テスト

aws CLIコマンドの" aws secretsmanager get-secret-value"を利用しシークレット情報を取得します。

 aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp

RDBにアクセスできるかを確認します。(この例ではMySQLエンジンを利用しています)

mysql --host=<RDSのエンドポイントDNS> --port=<Port番号> --user=<ユーザID> --password='<パスワード>'

リソースポリシーでシークレット情報取得を許可するVPCを制限する

SecretsManagerは、リソースポリシーを設定することが可能です。ただしマネージメントコンソールでは設定できなず、AWS CLIでの設定が必要になります。(ここではAWS CLIでSecrets Managerの管理設定を行うための準備作業は割愛します)

リソースポリシーの設定

今回は特定のVPC Endpoint以外からのリソース情報取得のためのアクセス(GetSecretValue API)を拒否するリソースポリシーを設定します。

AWS CLIを実行する端末上でリソースポリシー用のjsonファイルを用意します。"aws:sourceVpce"には先に作成した、SecretsManager用のVPC EndpointのARNを指定します。

{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Effect": "Deny",
       "Principal": "*",
       "Action": "secretsmanager:GetSecretValue",
       "Resource": "*",
       "Condition": {
         "StringNotEquals": {
           "aws:sourceVpce": "vpce-0b2b52e1dc7772d50"
         }
       }
     }
   ]
}
リソースポリシーのアタッチ*4

AWS CLIの”aws secretsmanager put-resource-policy ”を利用し、SecretsManagerのシークレット情報にリソースポリシーをアタッチします。

aws secretsmanager put-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp --resource-policy file://policy.json
動作テスト
  • (1) VPC内のAPサーバインスタンスからシークレット情報を取得可能なことを確認

AWS CLIを利用し、シークレット情報を取得します。(実際のアプリケーションではAWS SDKを利用しシークレット情報を取得します)

 aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp
  • (2)マネージメントコンソールからシークレット情報が取得できないことを確認

f:id:nopipi:20190212230338p:plain:w450

設定手順(ローテーションの設定)

RDBのDB管理者ユーザのログイン情報をシークレットに登録

ローテーション用のLambdaの中でDBMSのユーザ&パスワード更新を実行するため、admin権限のあるDBユーザをSecretsManagerに登録します。

リソースポリシーの一時解除

先に設定したリソースポリシーをアタッチしたままでは、ローテーションの設定が一部できないため、リソースポリシーを一時的に解除します。

aws secretsmanager delete-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp

ローテーションの有効化

  • 「ローテーションの編集」からローテーション設定を行います
  • 自動ローテーションを「有効化」します
  • ローテーションの間隔は、1-365日の間で設定します。
  • 「新しいLambda関数を作成して・・・」を選択します。これを選択するとCloudFormationからLamdbaやLambda実行に必要なIAMロールなどがデプロイされます
  • AWSシークレットマネージャで以前保存したシークレットを資料」を選択し、DBのadminユーザのシークレットを選択します。

f:id:nopipi:20190212231449p:plain

なお私の環境では、VPC内のLambdaで実行しようとするとLambda実行用のIAMロールのcondition設定がうまく働かずLambdaからSecretsManagerへの情報取得が失敗しました。一旦Condition句を削除して動作させるようにしています。

リソースポリシーの再アタッチ

AWS CLIの”aws secretsmanager put-resource-policy ”を利用し、SecretsManagerのシークレット情報にリソースポリシーを再アタッチします。

aws secretsmanager put-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp --resource-policy file://policy.json

ローテーションの確認

マネージメントコンソールの「すぐにシークレットを更新」か、AWS CLIの"aws secrets manager rotate-secret"を利用しシークレットの更新を行います。

f:id:nopipi:20190212233116p:plain:w400

(参考)ローテーション用のLambda関数の作成

ローテーション用のLambda関数を自作することもできます。自作する場合、下記にサンプルのローテーション関数があるのでこちらを参考にするのが良いと思います。

パターン認識と機械学習の詩的な説明にゾクゾク来た話

数年前、AIが流行り始めた時に機械学習がなんぞやと調べて時に出たったShieShareのイントロの「識別・認識とは?」の説明が、詩的ででもわかりやすくて、その時ゾクゾクと来たのを思い出したので、備忘録がてら引用しておきます。

ちなみに本文は数学者の方のスライドなので難しくてよくわかりませんでしたが(笑)

www.slideshare.net

上記SlideShareのP19-32から引用

認識とは、不要な情報を捨てること

特徴選択・特徴抽出が
識別・認識の本質

パターン認識機械学習においては
これを忘れてはいけません

色々な特徴や次元を
考えることは
とても役に立つことですが

知っている特徴や次元を
何も考えず全部手元に置いておくと
人間は高次元ユークリッド空間で
迷子になってしまいます

高次元ユークリッド空間は
私たちの感覚と乖離しやすく

もしあなたが無限次元の
ユークリッド空間に放り出されたら
見渡す限り全てのものが
あなたからはるかに遠くにあって
何も見分けがつかなるくなるような
そんな空間です

これは「次元の呪い」
と言われています

いいものも悪いものも
好きなものも嫌いなものも
関係あるものも関係ないものも

見分けがつかなくなってしまう
恐ろしい「呪い」ですね!

つまりあなたか
ヒルと白鳥の
雑多な集団の中から
白鳥を探し出しないのなら

まずあなたはあなたが
白鳥の
どの特徴を選択・抽出して
白鳥を白鳥と
認識しているのか
なるべく正確に
見つける必要があります

(2019/1)Appleのデバイスにプッシュ通知を行うためのAPNs設定メモ

はじめに

ここで説明すること

APNs(Apple Push Notification service)は、Appleのデバイス(iOSバイス、tvOS、macOS)に対してプッシュ通知を送るためのプラットフォームサービスです。*1
ここではアプリの通知の開発ができるようにするためのAPNsの設定を説明しています。

モバイルプッシュ関連のblog記事

全体の概要図

この記事で説明する全体の概要図です。(ProviderであるAmazon SNSへの個人情報交換ファイル取り込みは説明していません)

f:id:nopipi:20190201092820p:plain:w600

前提

  • Apple Developer Programの登録(有償)
    • プッシュ通知を利用した開発をするために必要
    • 料金は、年額で99ドル(個人または個人事業主/個人経営者)*2
    • 手順
      • Apple Developer Program - Apple Developerにアクセスする
      • 「登録」ボタンを押し、説明に従い情報を登録し、最後に料金を払う
      • 手続きが完了すると審査になります。審査には2日ほどかかる(審査中の場合、右上のログインユーザ名に"(pending)"と表示されます)
      • 審査が完了すると、メール通知がある
  • iOS開発環境

手順

iOSアプリ開発用証明書の作成

(1)Xcode連携での証明書作成

開発用途のiOSアプリの署名用に利用する証明書(以下、開発用証明書)をAPNsで作成します。手動もできますが、ここではXcode連携で作成します。

  • Xcodeを起動して、「Xcode」> 「Behaviors」> 「Edit Behaviors」を選択する

f:id:nopipi:20190126104647p:plain:w350

  • Apple IDとManage Certificates
    • 「Accounts」タブを選ぶ
    • Apple Developer Program登録したApple IDが登録できてない場合は左側の「Apple IDs」でID登録する
    • Apple Developer Program登録したApple IDを選択し、右下の「ManageCertificates」をクリックする

f:id:nopipi:20190126105602p:plain:w350

  • iOS Development」証明書の発行
    • 左下の「+」をクリックし、「iOS Development」を選択

f:id:nopipi:20190126113432p:plain:w350

  • 開発用の証明書が発行&登録される

f:id:nopipi:20190126114107p:plain:w350

(2)Apple Developerでの証明書確認

Apple Developerにログインして登録した証明書を確認できます。

f:id:nopipi:20190112015105p:plain:w350

  • 「Certificates」>「All」をクリックし登録した証明書を確認する

f:id:nopipi:20190126114917p:plain:w350

App ID の作成とNotificationsのSSLアクセス用証明書作成

(1)App ID作成

アプリケーションを識別するためのApp IDを登録します。

  • 「Identifiers」の「App IDs」をクリックし、右上の「+」をクリックする

f:id:nopipi:20190112022327p:plain:w300

  • 「Registering an App ID」で順に入力する
    • 「App ID Description」 > 「Name」: アプリケーションの名称を記載(例えばPushTest)
    • App ID Suffix
      • 「Explicit App ID」を選択し
      • 「Bundle ID」に、ユニークな名称を記載。通常はFQDNを利用し”work.nopipi.PushTest”のような感じにする
    • App Services
      • 「Push Notifications」にチェックを入れる(これ重要!!)
      • 「Continue」をクリック
  • 「Push Notifications」がConfigurableになっていることを確認し
  • 「Register」をクリック
(2) SSL証明書発行用に証明書署名要求(CSR)を作成

Macを利用して、CSR(Certificate Signing Request)を作成します。

  • キーチェーンアクセスを開きます
  • 「キーチェーンアクセス」>「証明書アシスタント」>「認証局に証明書を要求....」をクリックします
  • 必要事項を入力します
    • 「ユーザーのメールアドレス」を入力します
    • 「通称」は任意ですが、わかりやすい名称を記載(例えば"Bundle IDに設定した名前+SslCSR"とか)
    • 「CAのメールアドレス」は空欄
  • 「要求の処理」は「ディスクに保存」を選択ます
  • 「続ける」をクリックします

f:id:nopipi:20190112012806p:plain:w300
f:id:nopipi:20190112012932p:plain:w350

(3)NotificationsのSSL証明書作成
  • 作成したApp IDを開き、下段の「EDIT」をクリックする
  • 「Push Notifications」で、開発用のため「Development SSL Certificate」の「Creating Certificate」をクリック
  • SSL証明書の作成手順は以下の通り
    • Request:特になし。「Continue」をクリック
    • Generate: 準備したCSRを選択する。「Continue」をクリック
    • Download:「Download」から作成されたSSL証明書をダウンロードする。ダウンロードが完了したら「Done」する。
  • ダウンロードしたSSL証明書をダブルクリックしてキーチェーンに登録する
    • キーチェーンに登録したSSL証明書は、この後「APNs用証明書(.p12) の書き出し」で利用します。

f:id:nopipi:20190112083347p:plain:w400

バイス登録

(1)対象デバイスのUUID確認
  • Mac に端末を接続し、Xcodeを起動する
  • 「Window」>「Devices and Simulators」をクリック
  • 「identifier」としてUUIDが確認できます

f:id:nopipi:20190112031725p:plain:w400

(2)デバイスの登録
  • 「Devices」>「All」をクリックして、右上の「+」をクリック
  • 「Register Device」を選択し、端末の「Name」と「UUID」を入力
  • 完了したら「Continue」をクリックし、次の画面で「Register」をクリック

f:id:nopipi:20190112032143p:plain:w400

開発用プロビショニングプロファイルの作成

利用する App ID、開発用証明書、端末をそれぞれ紐付けプロビジョニングプロファイルを作成します。

  • 「ProvisioningProfiles」>「All」をクリックし、右上の「+」をクリック

f:id:nopipi:20190112080823p:plain:w350

  • What type of provisioning profile:
    • 「Development」>「iOS App Development」を選択する

f:id:nopipi:20190126121551p:plain:w350

f:id:nopipi:20190126121832p:plain:w350

  • Select certificates: 開発用証明書を選択
  • Select devices.:テスト用に登録したデバイスを選択
  • Name this profile and generate.:「Profile Name」にプロファイル名を設定
  • Profile Name: 「 Download」をクリックしてプロファイルをダウンロードする
  • ダウンロードが完了したら「Done」をクリック

作成したプロビショニングプロファイルは、Xcodeで開発したアプリに組み込みます。

APNs用個人情報交換ファイル(.p12) の作成

プロバイダー(サーバや、Amazon SNSAmazon PinpointなどAPNsにプッシュ通知依頼するもと)がAPNsアクセスするときに必要となるAPNs用証明書(.p12) を作成します。

f:id:nopipi:20190112084846p:plain:w400

f:id:nopipi:20190112085343p:plain

(備忘録)このblogのデザインめも

利用しているテーマ

blog.hatena.ne.jp

デザインCSS

/* <system section="theme" selected="6653812171397406126"> */
@import url("https://blog.hatena.ne.jp/-/theme/6653812171397406126.css");
/* </system> */

/* <system section="background" selected="bg5"> */
body{ background-color:#486079; background-image:url('/images/theme/backgrounds/theme5.jpg'); background-repeat: no-repeat; background-attachment:fixed; background-position: center top; background-size:cover; }
/* </system> */

table{ width:100%;} 
.scroll{ overflow: auto; white-space: nowrap;} 
.scroll::-webkit-scrollbar{height: 4px;} 
.scroll::-webkit-scrollbar-track{background: #F1F1F1;} 
.scroll::-webkit-scrollbar-thumb {background: #454545;}

@media screen and (min-width:1350px) {
  #box2 {
    float: right;
    width: 300px;
  }
  #main {
    float: right;
    width: 740px;
  }
  #wrapper {
    float: left;
    width: 1030px;
  }
  #content-inner {
    width: 1350px;
  }
}

CSSの参考にした情報

  • PC版でblogの幅を広げるCSS(for Naked)

www.shakkinhostess.com

  • 表の内容を折り返さずスクロールさせる

tamasaburo.com