AWS 利用時に、HTTPS 通信する方法いくつか

ドメイン認証でよいのであれば、https で通信する時は、AWS Certificate Managerで証明書を取得し、CloudFront で選択すれば良いが、いろんな条件でそれが出来ないことがあるため、そのときの対処方法と問題点です。

AWS Certificate Manager で、CNAME を利用した、DNS検証を使う

特に制限が無く、自身でRoute53やお名前.comなどのアカウントがある場合は、この方法で証明書を取得すればよい。
ただしこれの問題点は、文字の先頭に _ を使えないサービスでドメインを取得している場合は、利用できない。

AWS Certificate Manager で、Eメール検証を使う

WHOIS クエリで返された連絡先情報を使用するそのドメインの登録者、技術担当者、管理者の連絡先、ドメイン名の前に admin@、administrator@、hostmaster@、webmaster@、および postmaster@ のEメールが受信できるのであれば、検証できる。

受信を確認する担当者が別にいるような場合で、認証を行うまで3日以上かかる場合は、タイムアウトになってしまい、再度検証メールを送る必要がある。

そもそもメールが受信できない場合は利用出来ない。

AWS Certificate Manager で取得したリージョンを us-east-1 以外で取得してしまった場合

何らかの理由で、us-east-1 で取得し直すことが不可能な場合は、取得した証明書を Elastic Load Balancing に割り当てるしかない。
Elastic Load Balancing の後ろに EC2 を用いれば、あとはどうにか出来る。

ただしサーバー費が無駄に必要になる。

認証するドメインをNSレコードで登録

Route53で Hosted Zone を作成し、NSレコードとして別DNSサービス側に登録する。
これが出来れば、ドメインを所持している時と同じように設定できる。
サブドメイン単位でも登録出来るため、かなり自由がきく。

Let's Encrypt を用いて、証明書を取得する。

現在利用されているデバイスで、証明書が無効で通信できないようなことは起こっていないので、Let's Encryptは実用的に使えます。

これの利点は、利用するドメインの設定が終わっていて、特定のパスにファイルを置き、httpでアクセスできる状態なら、検証が出来るところ。
90日間で証明書の期限が切れてしまう。

# mac では実行できない。
$ git clone https://github.com/letsencrypt/letsencrypt.git
$ cd letsencrypt
$ ./certbot-auto certonly -m <EMAIL> -d <DOMAIN>

途中で、指定のURL、ファイルの内容で、ファイルをアップロードするように指示があるので、その通りにファイルを置く。
続けると、証明書が生成される。必要なのは、cert.pem (証明書), privkey.pem (プライベートキー), chain.pem (中間証明書)。



これで何かがおきた時、乗り切れるはず。

AWS Mysql に IAM Role で接続する

MySQL 5.6 マイナーバージョン 5.6.34 以降、MySQL 5.7 マイナーバージョン 5.7.16 以降、Amazon Aurora 1.10 以降 で対応している。

ただし、1秒間あたりの接続開始の認証回数が20回と少ないため、アクセスの多いシステムでは採用できない。
IAM データベース認証の制限

Lambda をVPC内に入れてしまうと、接続まで時間がかかるため、それを回避するために使ったりする。

1. RDS で Mysql を起動

  • パブリックアクセスを有効に変更
  • SSL 証明書をダウンロードする ( rds-combined-ca-bundle.pem )
  • セキュリティーグループは、0.0.0.0/0 などに変える。

パブリックアクセスを有効にする代わりに、SSL接続することになる。

2. Mysql にユーザーを作る

RDS 作成時の Root ユーザーで、IAM 用のユーザーを作る。

プラグインを有効にしユーザーを作成

CREATE USER 'iam_user'@'%' IDENTIFIED WITH AWSAuthenticationPlugin as 'RDS';

SSL 接続を強制する

GRANT SELECT,INSERT,UPDATE,DELETE ON dbdayo.* to 'iam_user'@'%' REQUIRE SSL;

3. IAM Policy を作成

作ったポリシーは、Roleなどにアタッチする。
太字の部分は固定値です。rds-db の部分も、これで間違いなく、Webコンソール上はエラーが出るが、あなたが正しい。

arn:aws:rds-db:{RDSのリージョン}:{AWS アカウントID}:dbuser:{RDSのリソースID}/{DBのUser名}

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds-db:connect"
            ],
            "Resource": [
                "arn:aws:rds-db:ap-northeast-1:1234567890:dbuser:db-AAAAARRRRRR/iam_user"
            ]
        }
    ]
}

4. Lambda や EC2 にRole を関連付ける

作ったPolicyをRoleにアタッチして、さらにそのRoleをLambdaやEC2に関連付ける。

5a. EC2などからプログラムで接続

RDS_HOST = 'dbdayo.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com'
RDS_USER = 'iam_user'
RDS_REGION = 'ap-northeast-1'

def lambda_handler(event, context):
    rds = boto3.client('rds')

    password = rds.generate_db_auth_token(
        DBHostname=RDS_HOST,
        Port=3306,
        DBUsername=RDS_USER
    )
 
    conn = mysql.connector.connect(
        user=RDS_USER,
        password=password,
        host=RDS_HOST,
        database='mysql',
        charset='utf8',
        ssl_verify_cert=True,
        ssl_ca='rds-combined-ca-bundle.pem' # ダウンロードしたファイルを指定
    )

5b. EC2からコマンドで接続する

aws rds generate-db-auth-token でパスワードを生成している、認証部分がポイント

mysql -u iam_user -h dbdayo.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com \
-p`aws rds generate-db-auth-token --hostname dbdayo.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com \
--port 3306 \
--username iam_user \
--region ap-northeast-1` \
--ssl-ca=rds-combined-ca-bundle.pem \
--enable-cleartext-plugin

最近 Apple の審査でリジェクトされた時の対応方法

Guideline 2.1 - Information Needed

We have started the review of your app, but we are not able to continue because we need access to a video that demonstrates Audio on background your app in use on a physical iOS device.

Please ensure the video you provide shows a physical iOS device (not a simulator).

Next Steps

To help us proceed with the review of your app, please provide us with a link to a demo video in the App Review Information section of iTunes Connect and reply to this message in Resolution Center.

To provide a link to a demo video:

  • Log in to iTunes Connect
  • Click on "My Apps"
  • Select your app
  • Click on the app version on the left side of the screen
  • Scroll down to "App Review Information"
  • Provide demo video access details in the "Notes" section
  • Click "Save"
  • Once you've completed all changes, click the "Submit for Review" button at the top of the App Version Information page.

Once this information is available, we can continue with the review of your app.

審査の時に、テスト方法を説明する動画をアップロードする必要がある。動画をスマホで撮影して、添付しました。

Guideline 2.1 - Information Needed


We have started the review of your app, but we are not able to continue because we need additional information about your app.

Next Steps

To help us proceed with the review of your app, please provide detailed information to the following questions. The more information you can provide upfront, the sooner we can complete your review.

  • What is the significant difference between this app and your ●●● app?

Once you reply to this message in Resolution Center with the requested information, we can proceed with your review.

自分が公開している、名前が似ているアプリがある場合、違いを説明する必要がありました。実際に中身が異なっていても、名前が似ているだけで必要です。

Guideline 2.2 - Performance - Beta Testing


Your app contains references to test, trial, demo, beta, pre-release or other incomplete content.

Specifically, the naming indicates that this is beta.

“●●● β”


Next Steps

To resolve this issue, please remove all references to "demo," "trial," "beta," or "test" in your app description, app icon, screenshots, previews, release notes, and binary. If you would like to conduct a beta trial for your app, you may wish to review the TestFlight Beta Testing Guide.

アプリタイトルに β の文字がある場合は、消す必要があります。

CloudFront の CNAME は、サブドメインであれば実質2個まで同じドメインが指定可能

CloudFront の CNAME の設定は、全CloudFrontでユニークにしなければなりませんが、
CloudFront の CNAME には、ワイルドカードでも指定できるため、
*.testdomain.testwww.testdomain.test で 2つ登録すれば、実質、同じドメインが指定できます。

ただし、Route53上では、Aレコードではなく、CNAMEレコードで登録する必要があります。

これが出来れば、何か移行作業時に助かるかもしれません。

一般提供された CloudFront lambda@Edge で、Basic認証を設定する

preview と 仕様が変わっています。

nodejsは6.10を選ぶ必要があり、headers の構造も変わっていました。
Cloudfrontのarn指定に、lambda を version がなければいけないのも、なかなかめんどくさい変更です。
あとは、role の設定も面倒ですが、一旦書きません。

"use strict";

exports.handle = (event, context, callback) => {
    
    const Allows = {
        "users": "users",
    };

    const request = event.Records[0].cf.request;
    const headers = request.headers;

    const authorization = headers.authorization || headers.Authorization;

    if (authorization) {

        const enc = authorization[0].value.split(" ")[1];
        const userPassword = new Buffer(enc, 'base64').toString();

        for (let key in Allows) {
            let val = Allows[key];
            if (`${key}:${val}` === userPassword) {
                callback(null, request);
                return;
            }
        }
    }

    const response = {
        status: '401',
        statusDescription: 'Authorization Required',
        httpVersion: request.httpVersion,
        headers: {
            "www-authenticate": [{key:"WWW-Authenticate", value: 'Basic realm="Enter username and password."'}],
            "content-type": [{ key: "Content-Type", value: "text/plain; charset=utf-8" }],
        },
        body: "401 Authorization Required",
    };

    callback(null, response);
};

CloudFront にCloudFront を入れるときの注意点

CloudFront は、Request header に含まれる Hostの値が、CloudFrontに設定されたCNAMEと一致していないとレスポンスを返さない。
CloudFrontに設定されたCNAMEは、すべてのCloudFrontで2つ同じCNAMEを設定できない。

Behavior の Forward Headers は、Host を含めた場合は、ブラウザがリクエストしたHostがそのままOriginまで到達するが、
含めない場合は、Originに設定したHostのまま、Originへリクエストする。
実はここがあまり書かれていないのでわかりにくい。

この条件を満たすため、
CloufFrontのOriginにCloudFront を含めるような場合は、Behavior の Forward Headers は、All が設定できず、Whitelist を使わなければならない。
たとえば All の代わりに、User-Agent、Authorization などを設定することになるはずです。

mysql5.7 の 注意点 (< 5.7.11)

RDS 上で mysql 5.7 を使うときに覚えておかなければならないことは一つで、

default_password_lifetime
この値が、5.7.10 以下の時、360 になっています。

SELECT @@default_password_lifetime;

つまり360日で期限切れになりログインできなくなります。RDS 作成時のマスターパスワードであっても同じです。

Your password has expired. To log in you must change it using a client that supports expired passwords.

万が一、期限が切れてしまった場合は、
RDSのマスターパスワードをリセットし、mysqlにログイン。

ALTER USER user_name PASSWORD EXPIRE NEVER;

これで password_lifetime = 0 となり、ログインできます。

5.7.11以降のバージョンは、default_password_lifetime = 0 になっているので、問題はありません。