[AWS,EC2]初期設定(インスタンス作成,SSH接続,料金のモニタリング)

AWSのアカウントを作成

https://qiita.com/Hikery/items/b919ae9e35f0f66e6a95

インスタンス作成

Step1 サービス > EC2 を選択

ec2.jpg

Step2 localの変更

time.jpg

Step3 マシーンイメージの選択

insutance.jpg

Step4 インスタンスタイプの選択

i_type.jpg

Step5 セキュリティグループの設定

・インスタンス設定
・ストレージ追加
はそのままで
・タグの追加 は適当にtagをつける。

セキュリティグループの設定 は HTTP を追加する。
security.jpg

Step6 キーペアを選択する

key2.jpg

鍵をDownloadして、インスタンスの作成をする。

SSH で繋いでみる

Step1 –

接続をおす
i_ssh_1.jpg

スタンドアロン SSH クライアント
i_ssh_1.jpg

Step2 – .pem fileを .ssh配下に配置する

terminal
$ mv /Users/[user name]/Downloads/***.pem /Users/[user name]/.ssh
$ chmod 600 football_chant.pem
$ ssh -i "***.pem" ec2-user@ec2-**-***-**-***.ap-northeast-1.compute.amazonaws.com
The authenticity of host 'ec2-**-***-**-***.ap-northeast-1.compute.amazonaws.com (**.***.**.***)' can't be established.
ECDSA key fingerprint is SHA***:*******************************************.
Are you sure you want to continue connecting (yes/no)?

yesを選択する。

terminal
Warning: Permanently added 'ec2-**-***-**-****.ap-northeast-1.compute.amazonaws.com,**.***.**.***' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/

環境によっては

terminal
$ sudo yum update

料金をモニターする

画面で料金を確認

右上のアカンウトクリック > 請求ダッシュボード
https://console.aws.amazon.com/billing/home#/
こんな感じで見れます。
price2.jpg

使用した料金をメールで受け取る。

https://console.aws.amazon.com/billing/home#/preference
とりあえず、全部受け取るようにする。
setting.jpg

請求アラートを管理する

“請求アラートを管理する”にLinkする。

アラート.jpg

アラームを作成

make.jpg

メトリック設定

メトリック : 請求
チェック : USD
時間 : 6時間
setting2.jpg

アラームの定義

0$を超えた時、0$に戻った時を指定します。
setting6.jpg

また心配であれば5ドルや10ドルを超えた時点でもアラートを出すと良いかと思います。

参考

AWSアカウントの保護

アカウントのセキュリティ保護のために下記の記事を参考に、
MFAデバイス認証をいれました。

https://qiita.com/tmknom/items/303db2d1d928db720888

料金

初心者なので、これは気をつけようと思いました。参考になります。
https://qiita.com/mochizukikotaro/items/a0e98ff0063a77e7b694

RDSでMySQLを起動させ、EC2のインスタンスにつなぐ

下記を参考にした。
https://qiita.com/na0AaooQ/items/7c69a88c80f1efb4cad3
https://qiita.com/hiroshik1985/items/6643b7323183f82297b2

続きを読む

Assume-role先のRoleの権限で(AWSの機能|vagrant|terraform|serverless|apex)を使いたい

背景

AWS CLIがAssumeRoleによる自動クレデンシャル取得とMFAに対応しました! | Developers.IO
awscliは上記で説明されているような記述を用いることにより、assume-role権限のあるroleへswitchしてコマンドを実行することができます。

しかし、この記述法は比較的最近導入されたこと、使用されることがそれほど多くないこと、内部的にSTSを使っているため自前で同様の仕組みを実装することは手間がかかることなどにより、通常 ~/.aws/credentials を見て自動的に認証情報を取得してくれるコマンドでもこのAssumeRole記法に対応してくれていないツールがあります(代表的なものにserverless, apex, terraform, vagrant-awsがあります)。

解決策

そこで、認証情報として環境変数が概ね優先されることを利用してラッパーコマンドを開発した人が結構います。
マイナーな欲求かつ簡単に実装できるため多数のリポジトリがありますが、以下がgithub上で自分が見つけた同様の目的のリポジトリ一覧です。

(※星の数は2018/01/09時点)

上記のリポジトリのうち、上2つは期待通り動くことを確認しました。
下3つはすみませんが動作確認をしていません。

結論

remind101/assume-role が期待通り動作しておりかつ星の数的にも定評があると思うので、機能的に問題なければそれを使えばいいと思います。

続きを読む

torilonの日記

Ubuntu-desktop だけでなく、Xfceとかをいれないとうまくいかなかった. AWSコンソールでvncのポートを開けないといけない. 6 iPad. Termius というアプリでssh 接続できた. 7 MFAにはGoogle Authenticatorをつかった。 最初のサインアップのときに、Google Authenticator の表示する数字を2回入力するところが最初分からず … 続きを読む

Evident.IO

AWSと連携させるとAWS上のセキュリティリスクを定期的に洗い出します。 例えば、. S3バケットがグローバルに公開されている; IAM UserのMFAが有効になっていない; 使用されていないアクセスキーがある. などです。 それぞれのリスクには修正するための手順も記載されており、その指示に従うことでリスクを軽減することが … 続きを読む

カテゴリー 未分類 | タグ

IAMユーザーのMFAをAWS CLIで無効化する

AWSでは、特権 のある IAM ユーザーに対して多要素認証(MFA)を有効にして AWS リソースを保護することが推奨されています。 MFA を有効にすることで、 ユーザー名とパスワード (ユーザーが既知の第 1 要素) と、 AWS MFA デバイスからの認証コード (ユーザーが所有している第 2 要素) の入力を求められます。 MFA 運用 … 続きを読む

はじめてのAWS Cognito!!

:santa:「Amazon Web Services Advent Calendar 2017」20日目の記事です

はじめに

今回、Advent Calendarへの投稿が「Qiita」デビューです。
あと、どうでも良い情報として、本日は、私の誕生日:birthday:です(四十路です・・)。

先日、「AWS SDK for JavaScript」を使用してCognitoを使用したのですが、諸々の用語や抑えどころが分からずに悩んだ点がいくつかあったので、「はじめてのAWS Cognito」と題してポイントをまとめてみました。

私自身も手探り感満載だったので、コメントやご助言頂けると嬉しいです!
Cognito Syncについては、まとめてないので、こちらを期待されている方は、スルーしてくださいw。

1.そもそもCognitoとは?

・ AWSが提供する認証・認可基盤です。通常は、IAMユーザーのアクセスキーや、インスタンスに対するIAMロールを使用して認証します。

2.なぜCognitoを使うのか?

・クライアントアプリ(SPAやスマホのネイティブアプリ)より直接AWSリソースへアクセスしたい要件が増えてきている中で、扱いに困るのがIAMユーザーのアクセスキーシークレットキーの扱いです。

特に、SPAのようなJavaScriptを使用したアプリケーションは、容易にブラウザのデバックツールより抜き取ることが可能なため、セキュリティ上問題があります。
また、仮になんらかの方法で、ファイルを難読化したとしても、永続的に権限を付与し続けることになるため、健全な運用ではありません。

そこで、Cognitoを使用してクライアントアプリからの認証を行い、IAMロールを使用して権限を払い出す仕組みを実現しています。

3.用語について

Cognitoで使用される用語を私なりにまとめてみました。

  • フェデレーティッドアイデンティティ
    どのようにして、認証を行うかの設定を行います。ソーシャルIDプロバイダー(FB、Twitter etc)の指定や、認証後の使用可能なAWSリソースのIAMロール設定等を行います。
     

  • ユーザプール
    「フェデレーティッドアイデンティティ」で作成されたIDプールに対してユーザの紐付けを行います。その際に使用するのが、ユーザプールです。
    どのアプリケーションに対して、どのような認証を行い(メール認証の有無や、MFA等)、パスワードポリシーの設定や、ユーザのアクティベーション等もあります。


4.どうやって使うのか

AWS SDK for JavaScriptを使用して、Cognito経由でDynamoDBへアクセスしてみます。

未認証でとりあえず使ってみる

まずは、フェデレーティッドアイデンティティを新規に作成して、未認証でも権限の払い出しをしてもらい、どんな感じになるか試します。

1. フェデレーテッドアイデンティティを作成する

  • 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」

    • ID プール名: 今回は、demo_cognito_unauthenticated
    • 「認証されていない ID に対してアクセスを有効にする」をチェックし、「プールの作成」
    • 「Your Cognito identities require access to your resources」は「許可」

スクリーンショット 2017-12-07 0.17.09.png


2. IAMロールの編集
DynamoDBへのアクセス許可の設定を追加します。
IAMから、ロールをクリックすると、以下のようなIAMロールが作成されて
いるはずです。

oneClick_Cognito_[ID プール名]Auth_Role_XXXXXXXXXXX
oneClick_Cognito_[ID プール名]UnAuth_Role_XXXXXXXXXXX

編集するロールを選択 -> 「ポリシーの編集」で以下のようにDynamoDBの権限を追加してください。
ここでは、
oneClick_Cognito_demo_cognito_unauthenticatedAuth_Role_XXXXXXXXXXX
を指定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*",
                "cognito-identity:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {   // 追加します。(コメントは追加時には削除しましょう。書式チェックで怒られます)
            "Effect": "Allow",
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/demo_cognito_table", // DynamoDBのARNを指定
            ]
        }       
    ]
}

3. DynamoDBにアクセスする

「AWS SDK for JavaScript」を使用すると、IdentityIdを取得することが出来ます。こちらのIDは、SDKがよろしく保持してくれるので、こちらで管理する必要はありません。

poolIdには、「フェデレーテッドアイデンティティ」のプールIDを指定します。プールIDにはユーザプールIDもあるので、ちょっと紛らわしいですね・・

以下は、DynamoDBのテーブルからのデータ取得例です。


var aws = require('aws-sdk');
var config = {
    poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    region: 'ap-northeast-1'        
};

aws.config.region = config.region;
aws.config.credentials = new aws.CognitoIdentityCredentials(
                                {IdentityPoolId: config.poolId});

aws.config.credentials.get(function(err) {
    if (!err) {
        console.log("Cognito Identify Id: " + aws.config.credentials.identityId);                

        // DynamoDBへ接続
        var dynamoDB = new aws.DynamoDB();
        var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});

        var params = {
            TableName : 'demo_cognito_table',
            Key: {
                'id': '1'
            }
        };  

        docClient.get(params, function(err, data) {
            if (!err){
                console.log(data);
            } else {
                console.log(err);
            }
        });        
    }
}); 

実行するとDynamoDBにアクセスして、データ取得できました。:v_tone1:

$ node unauth.js 
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }

DynamoDB周りのAPI仕様は別途ご確認ください。

未認証アクセスの用途としては、認証画面が存在しないアプリケーションで直接クライアントからAWSリソースに対してアクセスした場合等に使用することになると思います。

Cognitoユーザによる認証

ソーシャルIDプロバイダー(FB、Twitter etc)で認証することが実際の用途としては多いかなと思いますが、今回は、Cognitoの認証プロバイダを使用してみます。

Cognitoの認証プロバイダは、メールやSMSを使用したアクティベーションも可能です(アクティベーションメールのテンプレートもあります)が、諸々用意するのが大変なので、今回はnodeから直接認証のみを実施してみます(こちらを参考にさせて頂きました)。

1. Cognitoユーザーを作成
上記、記事の「2.AWS cognitoでユーザー作成」に沿って作成します。

スクリーンショット 2017-12-16 18.11.32.png

スクリーンショット 2017-12-16 18.13.20.png

2. フェデレーテッドアイデンティティを作成する
– 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」
– ID プール名: 今回は、demo_cognito_authenticated
– 「認証されていない ID に対してアクセスを有効にする」をチェックを外し、「プールの作成」
– 「Your Cognito identities require access to your resources」は「許可」

3. Amazon Cognito Identity SDK for JavaScriptのインストール
AWS SDK for JavaScriptと合わせて、
Amazon Cognito Identity SDK for JavaScriptを使用します。

$ npm install amazon-cognito-identity-js --save

4. DynamoDBにアクセスする
先程のDynamoDBアクセスを認証ありで行います。

var aws = require('aws-sdk');
var aws_cognito = require('amazon-cognito-identity-js');

var config = {
    poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
    region: 'ap-northeast-1'        
};

// ユーザープール設定
var user_pool = new aws_cognito.CognitoUserPool({
    UserPoolId : 'xxxxxxxx', // 1.で作成したユーザプールID
    ClientId : 'XXXXXXXXXXXXXXXXXXXX' // 1.で作成したアプリクライアント ID
});

// ユーザー決定
const cognito_user = new aws_cognito.CognitoUser({
    Username: 'XXXXX', // 1.でユーザに作成したユーザ名
    Pool: user_pool,
});

// パスワードの設定
const authentication_details = new aws_cognito.AuthenticationDetails({
    Password: 'XXXXXX', // 1.でユーザに設定した仮パスワード
});

// ユーザープール/ユーザー/パスワードを使って認証
cognito_user.authenticateUser(authentication_details, {
    // 成功時
    onSuccess(result){
        aws.config.region = config.region;
        aws.config.credentials = new aws.CognitoIdentityCredentials(
                                        {IdentityPoolId: config.poolId,
                                            Logins: {
                                                'cognito-idp.ap-northeast-1.amazonaws.com/<YOUR_USER_POOL_ID>': result.getIdToken().getJwtToken()
                                            }                                                                                    
                                        });

        // DynamoDBへ接続
        var dynamoDB = new aws.DynamoDB();
        var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});

        var params = {
            TableName : 'demo_cognito_table',
            Key: {
                'id': '1'
            }
        };  

        docClient.get(params, function(err, data) {
            if (!err){
                console.log(data);
            } else {
                console.log(err);
            }
        });    
    },
    onFailure(err){
        console.error(err);     
    },

    // 初回認証時のパスワード変更を仮パスワードで使いまわす。
    newPasswordRequired(user_attributes, required_attributes){
        cognito_user.completeNewPasswordChallenge(authentication_details.password, user_attributes, this);
    },
});

実行すると無認証時と同じく、DynamoDBにアクセスして、データ取得できました。:v_tone1:

$ node auth.js 
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }

意外と、Cognitoで認証後に取得したトークンと、IAMからCredentialを払い出すために繋ぎ込みが分からず、ハマりましたが、AWSのドキュメントにちゃんとありましたね・・

まとめ

ポイントを絞って初心者の方に分かりやすいようにまとめてみましたが、如何でしたでしょうか?
(‥‥というか、半分は自分への覚書ですが:sweat_smile:

Cognitoは、非常に使用用途が多いサービスですが、慣れないと用語が多く一度に理解するのは厳しいと感じました。色んな方が、書かれている優良な記事を参考にさせて頂きながら、やりたいことを整理して少しづつ小出しに理解していくのが良いように感じました。

続きを読む

スマートホームスキルの作成 – Cognito User Poolsを使って

スマートホームスキルとは

スマートホームスキルは、カスタムスキルと異なり、ユーザーが発話した内容を、プログラム用意なパラメーターにまで分解して呼び出してくれます。例えば、照明をつける場合、「Alexa、端末名をオンにして」といういうと、以下のようなDirectivesという形でスマートホームスキルが呼び出されます。

{
  "directive": {
    "header": {
      "namespace": "Alexa.PowerController",
      "name": "TurnOn",
      "payloadVersion": "3",
      "messageId": "1bd5d003-31b9-476f-ad03-71d471922820",
      "correlationToken": "dFMb0z+PgpgdDmluhJ1LddFvSqZ/jCc8ptlAKulUj90jSqg=="
    },
    "endpoint": {
      ...
}

一般的なWebAPIの呼び出しと変わらない形で呼んでくれますので、会話の組み立てなどを考える必要がなく開発する側は非常に楽です。

image.png

カスタムスキルの場合は、会話が分解されて文字列としてスキル側に渡されます。そののため各言語ごとの処理が必要になります。しかしスマートホームスキルの場合は、その辺りの処理はAlexaが行ってくれるので、他言語化対応ができます。

以下の照明のON/OFFの場合、英語(米国)、英語(英国)、英語(インド)、ドイツ語、日本語の5ヶ国語に対応が可能です。
https://developer.amazon.com/ja/docs/device-apis/alexa-powercontroller.html

やりたいこと

自前デバイスを制御するためのスマートホームスキルの作成方法を理解する。デバイスは自前クラウド経由で制御が可能。自前クラウドはCognito User Poolsでアカウント管理を行っており、AlexaのAmazonアカウントと連携して制御可能とする。(アカウントリンク)

開発者コンソールでスキルの登録

Amazon開発者コンソールでスキルを登録します。
https://developer.amazon.com/home.html

スクリーンショット 2017-12-17 12.30.01.png

以下のように設定してスキルを作成します。後からLambdaなどの設定をするので、まずははアプリケーションIDだけ取れれば良いです。
スクリーンショット 2017-12-17 12.30.41.png

AWS Lambdaでスマートホームスキルの作成

AWSコンソールでスマートホームスキルをLambdaで作成します。Lambdaには、スマートホームスキルの雛形が用意されていますので、まずはそれを利用します。”設計図”、”alexa-smart-home-skill-adapter”を選択します。Amazonに確認したわけではないですが、tokyoリージョンにLambdaを作成した時は後にエラーになりました。us-east-1を選択して下さい。
スクリーンショット 2017-12-17 16.42.19.png

以下のようにLambdaの設定をします。アプリケーションIDは先ほど作成したスマートホームスキルのIDを設定します。
スクリーンショット 2017-12-17 16.57.45.pngスクリーンショット 2017-12-17 16.57.53.png

Lambdaが作成されました。後ほどARNをスキルの設定で利用します。
スクリーンショット 2017-12-17 17.03.40.png

Cognito User Poolsの設定

次にアカウント管理のためのCognito User Poolsの設定をしていきます。AWSコンソールよりユーザープールを作成します。ステップに従って設定するを選択します。
スクリーンショット 2017-12-17 17.07.23.png

スクリーンショット 2017-12-17 17.08.28.png

基本的な仕組みを確認するためなので、属性などはここでは必要ありません。以下のように設定をしていきます。

  • 属性

    • 標準属性 – なし
    • カスタム属性 – なし
  • ポリシー
    • パスワード強度:デフォルト 8文字
    • ユーザーの自己サインアップ:デフォルト 許可する
    • 有効期限:デフォルト 7日間
  • MFA
    • MFA:OFF
    • 検証:e-mailのみ
  • メッセージのカスタマイズ
    • E メール検証メッセージをカスタマイズ:デフォルト
    • ユーザー招待メッセージをカスタマイズ:デフォルト
    • E メールアドレスをカスタマイズ:デフォルト
  • タグ/デバイスはスキップして次へを選択
  • 「アプリクライアント」で「アプリクライアントの追加」

スクリーンショット 2017-12-17 17.34.02.png

あとは次へを選択してプールを作成。次にスマートホームスキルに設定するための以下の二つの情報を取得。

  • アプリクライアントID
  • 「アプリの統合」「ドメイン名」をクリックして、適当なドメインを設定
    スクリーンショット 2017-12-17 17.45.42.png

スクリーンショット 2017-12-17 21.45.48.png

スキルの設定

Alexaのコンソールの設定に戻って、以下の設定をします。

  • LambdaのARNの設定
  • アカウントリンクの設定

スクリーンショット 2017-12-17 21.47.49.png

スクリーンショット 2017-12-17 21.48.01.png

コールバックURIは次の設定で利用します。

スクリーンショット 2017-12-17 21.49.00.png

Cognito User PoolsにコールバックURIの設定

先ほど取得したOAuthのコールバックURIを以下のように設定します。

スクリーンショット 2017-12-17 22.00.35.png

動作確認

後ほどアップデートします

続きを読む

AWSの次世代JavaScriptライブラリ「AWS Amplify」

AWS Amplifyとは? 本記事はServerless Advent Calendar 2017の13日目の記事です。よろしくお願いします。 AWS Amplifyは、2017年11月に公開されたAWSを利用するWebアプリケーション向けのJavaScriptライブラリです。サインアップやサインイン、MFA、追跡またはメトリクスの分析、コンテンツ管理、またはサーバー … 続きを読む

CloudFormationを使って一撃で作るAssumeRoleによる強い💪権限管理

インフラエンジニアのみつの(@kotatsu360)です。
この記事はVASILY Advent Calendar 201710日目の記事です。

この記事では、AWSのIAMでAssumeRoleする権限周りを一撃でつくるCloudFormationテンプレートをまとめます。ご査収ください。

CloudFormationが作る環境のイメージ
image.png

このドキュメントの目的

IAMは調べれば調べるほど情報が断片的になる。あとJSON書くの面倒(一一 )
CloudFormationならYAMLで書けるし再現性がある。テンプレートにまとめようヽ(゚∀゚)ノ パッ☆

AssumeRoleとは

  1. 役割ごとに必要な権限を持ったIAMロールを作っておく

    • 開発
    • 運用
    • 請求
    • 監査
    • etc…
  2. IAMロールごとに「自分の権限を使うことを許可する」対象を設定しておく
    • 開発用のロールはエンジニアAとBとCと…
    • IAMロール「力がほしい時はいつでも我が名を呼ぶが良い」
  3. つかう
    • 変身
    • 普段はブラックRX。たまにはバイオライダー。

メリット

  • 権限をロールという単位で整理できる

    • 個人ごとに細かく設定するとスパゲッティになりがち
  • 場面場面で必要な権限だけが使える
    • 「開発時に誤って本番構成を変更してしまって泣く」ということが減る
  • 権限の確認が楽
    • 個人ごとに設定すると、権限付与者(おそらく強い権限持ち)と非付与者の差異が生まれる
    • AssumeRoleであれば、そのロールにスイッチして自分で権限を確認できる

デメリット

  • めんどう

    • 「rootアカウントでいいじゃん」と言われたらそこまで・・・
    • アカウント管理をやりたい時はとてもオススメ

なお、後から入れるのはカロリーを消費するので導入は早い方が良いと思います。
また、CloudFormationを使うとコード管理できるので、かなり楽になります。

CloudFormationテンプレートで実行されること

  • IAMユーザの作成

    • ユーザは4人
    • 開発者
    • 開発者&本番運用者
    • 開発者&本番運用者
    • 請求管理者
    • 初ログイン時にパスワード変更画面を出す
  • IAMグループの作成
    • 全員用のグループ
    • 本番運用者用のグループ
  • IAMロールの作成
    • 開発者用の権限を管理するロール
    • 本番運用者用の権限を管理するロール
    • 請求管理者用の権限を管理するロール
  • ユーザをグループに追加

グループとロールの住み分けについては後で触れます。

CloudFormationテンプレート

初期パスワードが小文字と記号になっているので、アカウントのパスワードポリシーによっては作成に失敗します。

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: 'IAM User Name'
        Parameters:
          - Dev1
          - Prod1
          - Prod2
          - Billing1
Parameters:
  Dev1:
    Type: String
    Default: 'kotatsu360a'
  Prod1:
    Type: String
    Default: 'kotatsu360b'
  Prod2:
    Type: String
    Default: 'kotatsu360c'
  Billing1:
    Type: String
    Default: 'kotatsu360d'
Resources:
  # ユーザ全員が所属するグループ
  IAMGroupAllMember:
    Type: 'AWS::IAM::Group'
    Properties:
      Policies:
        - PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'iam:List*'
                Resource: '*'
              - Effect: 'Allow'
                Action:
                  - 'iam:GetLoginProfile'
                  - 'iam:ChangePassword'
                  - 'iam:CreateVirtualMFADevice'
                  - 'iam:DeleteVirtualMFADevice'
                  - 'iam:EnableMFADevice'
                Resource: 
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}'
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username}'
             - Effect: 'Allow'
                Action:
                  - 'am:DeactivateMFADevice'
                Resource:
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}'
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username}'
                Condition:
                  Bool:
                    aws:MultiFactorAuthPresent: true
          PolicyName: 'mfa-attach'

  # 本番運用者が所属するグループ
  IAMGroupProductionOperator:
    Type: 'AWS::IAM::Group'
    Properties:
      Policies:
        - PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'opsworks:UpdateMyUserProfile'
                  - 'opsworks:Describe*'
                Resource: '*'
          PolicyName: 'change-my-ssh-key'

  # [NOTE] 開発者と請求管理者については個人宛のルールが必要ないのでグループを作らない

  # 開発者の権限を管理するロール
  IAMRoleDeveloper:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'developer'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !GetAtt IAMUserDev1.Arn
                - !GetAtt IAMUserProd1.Arn
                - !GetAtt IAMUserProd2.Arn
            Action: 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/ReadOnlyAccess'

  # 本番運用者の権限を管理するロール
  IAMRoleProductionOperator:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: 'production-operator'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !GetAtt IAMUserProd1.Arn
                - !GetAtt IAMUserProd2.Arn
            Action: 'sts:AssumeRole'
            Condition:
              Bool:
                aws:MultiFactorAuthPresent: true
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/ReadOnlyAccess'
        - 'arn:aws:iam::aws:policy/AmazonS3FullAccess'

  # 請求管理者の権限を管理するロール
  IAMRoleBillingOwner:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: 'billing-owner'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !GetAtt IAMUserBilling1.Arn
            Action: 'sts:AssumeRole'
            Condition:
              Bool:
                aws:MultiFactorAuthPresent: true
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/job-function/Billing'

  IAMUserDev1:
    Type: 'AWS::IAM::User'
    Properties:
      LoginProfile:
        Password: 'i_love_whisky'
        PasswordResetRequired: true
      UserName: !Ref Dev1

  IAMUserProd1:
    Type: 'AWS::IAM::User'
    Properties:
      LoginProfile:
        Password: 'i_love_cigar'
        PasswordResetRequired: true
      UserName: !Ref Prod1

  IAMUserProd2:
    Type: 'AWS::IAM::User'
    Properties:
      LoginProfile:
        Password: 'i_love_sleeping'
        PasswordResetRequired: true
      UserName: !Ref Prod2

  IAMUserBilling1:
    Type: 'AWS::IAM::User'
    Properties:
      LoginProfile:
        Password: 'i_love_money'
        PasswordResetRequired: true
      UserName: !Ref Billing1

  IAMUserToGroupAdditionAllMember:
    Type: 'AWS::IAM::UserToGroupAddition'
    Properties:
      GroupName: !Ref IAMGroupAllMember
      Users:
        - !Ref IAMUserDev1
        - !Ref IAMUserProd1
        - !Ref IAMUserProd2
        - !Ref IAMUserBilling1

  IAMUserToGroupAdditionProductionOperator:
    Type: 'AWS::IAM::UserToGroupAddition'
    Properties:
      GroupName: !Ref IAMGroupAllMember
      Users:
        - !Ref IAMUserProd1
        - !Ref IAMUserProd2

権限の補足

IAMグループの使いどころ

権限は次の方針で設定しています。

  • ユーザ自体には何の権限も与えない
  • IAMロールで権限管理

しかし、幾つかの権限はロール管理が難しいです。

  • 自分のパスワードの変更

    • 特に、初ログイン時のパスワード変更はユーザ権限での操作以外ムリ
  • 自分のMFA設定
  • 自分のSSH鍵管理
    • OpsWorksを使う場合

「自分の」という部分が曲者です。単に権限を与えるだけでなく、「自分だけできる」というのが重要です。
そのため、これら「自分の情報だけに対して更新権限を与えたい」という場合はIAMグループを使って権限付与しています。

              - Effect: 'Allow'
                Action:
                  - 'iam:GetLoginProfile'
                  - 'iam:ChangePassword'
                  - 'iam:CreateVirtualMFADevice'
                  - 'iam:DeleteVirtualMFADevice'
                  - 'iam:EnableMFADevice'
                Resource: 
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:mfa/${!aws:username}' # 自分のMFAだけを対象に
                  - !Sub 'arn:aws:iam::${AWS::AccountId}:user/${!aws:username} # 自分のユーザ情報だけを対象に

OpsWorksはActionレベルで自分だけに対してのものを用意してくれているのでそれを使います。

              - Effect: 'Allow'
                Action:
                  - 'opsworks:UpdateMyUserProfile' # 自分の情報だけの更新権限, 参照権限版もある(DescribeMyUserProfile)
                  - 'opsworks:Describe*'
                Resource: '*'

AssumeRoleの条件

AssumeRoleは、ユーザの指定以外にも特定の条件を満たした場合のみ、という制約をつけることができます。

本番運用者と請求管理者にはユーザの指定以外にMFAでログインしている場合のみAssumeRoleを許可するという制約をつけました。

      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS:
                - !GetAtt IAMUserBilling1.Arn
            Action: 'sts:AssumeRole'
            Condition:
              Bool:
                aws:MultiFactorAuthPresent: true # MFAログインでないとConditionが満たせずAssumeRoleできない

さいごに

AssumeRoleを理解してからは権限管理の世界が広がった感があります。
ぜひ権限を追加して、実態に即したロールに育ててください。

さいごのさいごに

(IAMの具体的な使い方を紹介する記事がもっと増えますように)

続きを読む