2021年10月18日月曜日

blogspotのGoogleSearchでサーバーエラー(5xx)になる

 

いつのまにか、GoogleSearchで5XXエラーが多発するようになっていた。


下記記事を参考に対処したら、エラーは出なくなりました。

https://www.amanchourasia.in/2021/06/how-to-fix-server-error-5xx-in-blogger.html







2021年7月4日日曜日

docker の rainで cloudformation してみる

 

rain の dockerイメージを作ります。

Dokerfileは以下のとおり。

User, Group は、rain を使用するユーザに合わせています。

FROM amazon/aws-cli:latest

ARG RAIN_VER=1.2.0
ARG UID=1000
ARG GID=1000
ARG GNM=ubuntu
ARG UNM=ubuntu

ADD https://github.com/aws-cloudformation/rain/releases/download/v${RAIN_VER}/rain-v${RAIN_VER}_linux-amd64.zip /tmp/rain.zip

# Install Rain
RUN yum install unzip -y \
 && unzip -j /tmp/rain.zip */rain -d /usr/local/bin/ \
 && chmod 755 /usr/local/bin/rain \
 && rm /tmp/rain.zip

# user
RUN echo "${GNM}:x:${GID}:${UID}" >> /etc/group
RUN echo "${UNM}:x:${UID}:${GID}::/home/ubuntu:/sbin/nologin" >> /etc/passwd

ENTRYPOINT ["/usr/local/bin/rain"]


ビルドします。

$ docker build . -t aws-rain


ビルドしたDockerイメージを確認します。

$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),117(netdev),1001(docker)
$ docker run --rm --entrypoint bash aws-rain -c "id ubuntu"
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)
$ docker run --rm aws-rain --version
Rain v1.2.0 linux/amd64


Dockerイメージを実行するスクリプトを用意します。

今回は、/usr/local/bin/rain にします。

内容は以下のとおり。

$ cat /usr/local/bin/rain
#!/bin/bash
docker run -it --rm -v $HOME:$HOME -u ubuntu -w $PWD aws-rain $*

実行権限をつけます。

$ chmod +x /usr/local/bin/rain


rainの動作確認をします。

$ rain ls --profile sandbox
CloudFormation stacks in us-east-1:
  Blue21VpcPoC: CREATE_COMPLETE


docker イメージにはホームディレクトリをマウントしているので、CFNテンプレートをホームディレクトリに置いて、rainを使うようにします。

また、上記の例だと、PC側のubuntuユーザにaws-cli の設定(~/.aws)が必要です。


2021年7月3日土曜日

EC2インスタンスのタグ(Name)とSSMでSSHしてみる

 

EC2インスタンスのタグ(Name)でSSHしてみたいと思います。


まず、SSMで ssh できることを確認します。

セットアップの手順は下記ページを参考にしてください。


~/.ssh/config は下記のとおり。

Host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --profile sandbox --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"


下図のようにssh接続します。

aws-cliを実行するので、接続するまで、少し遅いです。


こんどは、~/.ssh/config は下記のようにします。

"--target" に指定するインスタンスIDを aws-cli で検索します。

なお、%h は大文字を小文字に置き換えるので、EC2インスタンスのタグ(Name)は、アルファベット小文字にしないと失敗します。

Host sbx-*
    ProxyCommand bash -c "aws ssm start-session --profile sandbox --target $(aws ec2 describe-instances --profile sandbox --filters "Name=tag:Name,Values=%h" "Name=instance-state-name,Values=running" --query "Reservations[].Instances[].InstanceId" --output text) --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"


下図のようにEC2インスタンスのタグ(Name)でssh接続します。

aws-cli を2回実行するので、接続するまで、さらに遅いです。




2021年7月1日木曜日

Linux Mint 20.1 でwi-fi 接続が切れまくる


下記の古いマシンに「Linux Mint 20.1」をインストールしました。



 WiFiが切れまくる


LANケーブルでのネット接続は問題なかったのですが、wi-fi が切れまくります。

1~3分ぐらいで切れます。

lspci は下記のとおり

$ lspci
00:00.0 Host bridge: Intel Corporation 3rd Gen Core processor DRAM Controller (rev 09)
00:02.0 VGA compatible controller: Intel Corporation 3rd Gen Core processor Graphics Controller (rev 09)
00:14.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller (rev 04)
00:16.0 Communication controller: Intel Corporation 7 Series/C216 Chipset Family MEI Controller #1 (rev 04)
00:1a.0 USB controller: Intel Corporation 7 Series/C216 Chipset Family USB Enhanced Host Controller #2 (rev 04)
00:1b.0 Audio device: Intel Corporation 7 Series/C216 Chipset Family High Definition Audio Controller (rev 04)
00:1c.0 PCI bridge: Intel Corporation 7 Series/C216 Chipset Family PCI Express Root Port 1 (rev c4)
00:1c.1 PCI bridge: Intel Corporation 7 Series/C210 Series Chipset Family PCI Express Root Port 2 (rev c4)
00:1c.2 PCI bridge: Intel Corporation 7 Series/C210 Series Chipset Family PCI Express Root Port 3 (rev c4)
00:1d.0 USB controller: Intel Corporation 7 Series/C216 Chipset Family USB Enhanced Host Controller #1 (rev 04)
00:1f.0 ISA bridge: Intel Corporation HM76 Express Chipset LPC Controller (rev 04)
00:1f.2 SATA controller: Intel Corporation 7 Series Chipset Family 6-port SATA Controller [AHCI mode] (rev 04)
00:1f.3 SMBus: Intel Corporation 7 Series/C216 Chipset Family SMBus Controller (rev 04)
01:00.0 Network controller: Ralink corp. RT3290 Wireless 802.11n 1T/1R PCIe
01:00.1 Bluetooth: Ralink corp. RT3290 Bluetooth
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL810xE PCI Express Fast Ethernet controller (rev 05)
03:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS5229 PCI Express Card Reader (rev 01)

ネットで調べると、

「ipv6 が悪さすることがあるらしい。」

ということで、

ipv6 を無効にして、OS再起動してみましたが、効果ありませんでした。

/etc/sysctl.conf  の修正内容は下記のとおり。

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1


/var/log/syslog を見ると下記のようなメッセージがでています。

Jun 27 21:36:10 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 
Jun 27 21:36:12 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: message repeated 2 times: [ wlo1: CTRL-EVENT-BEACON-LOSS ]
Jun 27 21:36:13 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 
Jun 27 21:36:14 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 
Jun 27 21:36:15 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 
Jun 27 21:36:18 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 
Jun 27 21:36:27 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: message repeated 9 times: [ wlo1: CTRL-EVENT-BEACON-LOSS ]
Jun 27 21:36:28 HP-Pavilion-g6-Notebook-PC wpa_supplicant[612]: wlo1: CTRL-EVENT-BEACON-LOSS 


さらに、調べていると、

「wi-fiの省電力モードが悪さすることがあるらしい。」

といことで、

wi-fiの省電力モードを無効にしました。

/etc/NetworkManager/conf.d/default-wifi-powersave-on.confの修正内容は下記のとおり。

[connection]
#wifi.powersave = 3
wifi.powersave = 2


OS再起動すると、wi-fi が切れなくなりました。

省電力モードが悪さしてたようです。

問題解消です。

ちなみに、syslog には、前述のメッセージが出なくなりました。



chrome


最初は、chromium を入れてみたのですが、Googleアカウントへのログイン状態が維持されなかったので削除しました。

GoogleのChromeを入れたら、ちゃんと動いてます。



VirtualBox


「このPCがSecureBoot環境」なので、VirtualBox のインストールではパスワード入力を求められます。

パスワード(12345678)を入力して、再起動すると、見慣れないBOOTメニューが表示されますが、ここから MOK の登録作業が必要です。

ContinueせずEnroll MOKを選択し、先ほど設定したパスワードを入力して、キーを Enroll(登録)したら rebootします。

これでVirtualBoxが使えるようになります。

$ /etc/init.d/virtualbox status
● virtualbox.service - LSB: VirtualBox Linux kernel module
     Loaded: loaded (/etc/init.d/virtualbox; generated)
     Active: active (exited) since Wed 2021-06-30 07:20:08 JST; 8min ago
       Docs: man:systemd-sysv-generator(8)
    Process: 950 ExecStart=/etc/init.d/virtualbox start (code=exited, status=0/SUCCESS)

 6月 30 07:20:07 HP-Pavilion-g6-Notebook-PC systemd[1]: Starting LSB: ….
 6月 30 07:20:07 HP-Pavilion-g6-Notebook-PC virtualbox[950]:  * Loadin….
 6月 30 07:20:08 HP-Pavilion-g6-Notebook-PC virtualbox[950]:    ...done.
 6月 30 07:20:08 HP-Pavilion-g6-Notebook-PC systemd[1]: Started LSB: V….
Hint: Some lines were ellipsized, use -l to show in full.


開発用にいれたものたち


  • emacs 26.3
  • docker 20.10.7
  • docker-compose 1.25.0
  • virtualbox 6.1.16
  • vagrant 2.2.6
  • aws-cli 2.2.14
    • session-manager-plugin 1.2.205.0-1
    • awscli-plugin-endpoint 0.4
    • aws-mfa 0.0.12
  • sam-cli 1.24.1
  • homebrew 3.2.0
    • rain 1.2.0



2021年6月27日日曜日

awsでスイッチロールしてみる

 

下記要件でクロスアカウントでスイッチロールしてみます。


IAMユーザ用アカウントでの作業


作成するもの
  • IAMロール(スイッチ用)
  • IAMグループ(ログイン用)
  • IAMユーザ(ログイン用)

IAMロール作成


スイッチ用のロールを作ります。
IAMユーザでログイン後、このロールにスイッチして「IAMユーザ用アカウント」で作業するようにします。

CloudFromationテンプレートのサンプルは下記のとおり。
パラメータの${AccountId} の部分には、「IAMユーザ用アカウント」のAWSアカウントIDを指定します。
ConditionでスイッチするIAMユーザ名の有無をチェックしています。この条件は、Versionが 2012-10-17 より古いと使用できないようです。
ちなみに、rain は、IAMユーザ名を伝えられないようなので、rainを使いたい場合は、このConditionは削除したほうが良さそうです。
  SwitchRoleDev:
    Type: AWS::IAM::Role
    Properties:
      RoleName: Blue21DemoDevRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: Allow
          Principal:
            AWS:
              - !Sub arn:aws:iam::${AccountId}:root
          Action:
            - 'sts:AssumeRole'
          Condition:
            StringLike:
              sts:RoleSessionName: ${aws:username}
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess
        - arn:aws:iam::aws:policy/IAMReadOnlyAccess
      Policies:
        - PolicyName: accesskey-fullaccess
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "iam:DeleteAccessKey"
                  - "iam:GetAccessKeyLastUsed"
                  - "iam:UpdateAccessKey"
                  - "iam:CreateAccessKey"
                  - "iam:ListAccessKeys"
                Resource: "arn:aws:iam::「IAMユーザ用アカウントのID」:user/${aws:username}"

「IAMユーザ用アカウント」の、このロールにはアクセスキーを作成する権限を与えます。

IAMグループ作成


IAMユーザ用のグループを作成します。
グループに設定するポリシーでは、「パスワード変更」、「MFA設定」、「スイッチロール」ができるだけの最小限の権限を与えます。

CloudFromationテンプレートのサンプルは下記のとおり。
  DevGroupPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: Blue21DemoDevUser
      Groups:
        - !Ref DevGroup
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Sid: "VisualEditor0"
          Effect: "Allow"
          Action:
          - "iam:ChangePassword"
          Resource: "arn:aws:iam::*:user/${aws:username}"
        - Sid: "VisualEditor1"
          Effect: "Allow"
          Action:
          - "iam:GenerateCredentialReport"
          - "iam:Get*"
          - "iam:List*"
          - "iam:SimulatePrincipalPolicy"
          - "iam:SimulateCustomPolicy"
          - "iam:GenerateServiceLastAccessedDetails"
          Resource: "*"
        - Sid: "VisualEditor2"
          Effect: "Allow"
          Action:
          - "iam:DeactivateMFADevice"
          - "iam:EnableMFADevice"
          - "iam:ResyncMFADevice"
          - "iam:ListMFADevices"
          Resource: "arn:aws:iam::*:user/${aws:username}"
        - Sid: "VisualEditor3"
          Effect: "Allow"
          Action:
          - "iam:DeleteVirtualMFADevice"
          - "iam:CreateVirtualMFADevice"
          Resource: "arn:aws:iam::*:mfa/${aws:username}"
        - Sid: "VisualEditor4"
          Effect: "Allow"
          Action:
          - "sts:AssumeRole"
          Resource: "arn:aws:iam::*:role/Blue21DemoDevRole"
          Condition:
            BoolIfExists:
              aws:MultiFactorAuthPresent: "true"
  DevGroup:
    Type: AWS::IAM::Group
    Properties:
      GroupName: Blue21DemoGroupDev
      Path: /

IAMユーザ作成


IAMユーザを登録します。
aws-cli だと下記のとおり。
このユーザには、AWSコンソールのログインを許可します。
$ aws iam create-user --user-name user-dev01
$ aws iam create-login-profile --user-name user-dev01 --password P@ss20210627 --password-reset-required
$ aws iam add-user-to-group --user-name user-dev01 --group-name Blue21DemoGroupDev

開発用アカウントでの作業


作成するもの
  • IAMロール(スイッチ用)

IAMロール作成


スイッチ用のロールを作ります。
「IAMユーザ用アカウント」のユーザが、このロールにスイッチして「開発用アカウント」で作業するようにします。

CloudFromationテンプレートのサンプルは下記のとおり。
前述の「IAM用アカウント」で作成したロールとの違いは、「アクセスキー」を操作する権限がないことだけです。
パラメータの${AccountId} の部分には、「IAMユーザ用アカウント」のAWSアカウントIDを指定します。
ConditionでスイッチするIAMユーザ名の有無をチェックしています。
  SwitchRoleDev:
    Type: AWS::IAM::Role
    Properties:
      RoleName: Blue21DemoDevRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: Allow
          Principal:
            AWS:
              - !Sub arn:aws:iam::${AccountId}:root
          Action:
            - 'sts:AssumeRole'
          Condition:
            StringLike:
              sts:RoleSessionName: ${aws:username}
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/AmazonEC2FullAccess

AWSコンソールで確認


AWSコンソールで「IAMユーザ用アカウント」にログインすると、初回のみパスワード変更を要求されます。
試しに、MFAを設定せずに、スイッチロールしてみるとエラーになりましました。

MFAを設定して、ログインし直すと、スイッチロールできます。
スイッチロールすれば、Blue21DemoDevRoleの権限で作業できます。
下図の左が「ログインしたアカウントの情報」、右が「スイッチした先のアカウントの情報」になります。

「IAMユーザ用アカウント」から「開発用アカウント」へもスイッチできます。

なお、このユーザが所属するグループは、Blue21DemoDevRoleへのスイッチしか許可していないので、他のロールにスイッチしようとするとエラーになります。

MFAの設定は下記ページ参照。
ChromeでGoogle Authenticator使うと便利です。

Chromeで複数アカウントを使い分けたいときは、下記ページ参照

Chromeからスイッチロールの履歴を削除したい場合は、下記ページ参照

Chromeでスイッチロールを便利に使う方法は、下記ページ参照

aws-cli で確認


まず、アクセスキーを作ります。

AWSコンソールで「IAMユーザ用アカウント」にログインします。
ログインしただけではアクセスキーを作成する権限がないので、Blue21DemoDevRoleにスイッチして、アクセスキーを作成します。

次に、aws-cli の設定をします。

~/.aws/config の設定は下記のとおり。
blue21-iam が「IAMユーザアカウント」用

[profile blue21-iam]
region = us-east-1
output = json

[profile blue21-dev]
region = us-east-1
output = json
role_arn = arn:aws:iam::「IAMユーザ用アカウントのID」:role/Blue21DemoDevRole
mfa_serial = arn:aws:iam::「IAMユーザ用アカウントのID」:mfa/user-dev01
role_session_name = user-dev01
source_profile = blue21-iam

[profile sandbox-dev]
region = us-east-1
output = json
role_arn = arn:aws:iam::「開発ユーザ用アカウントのID」:role/Blue21DemoDevRole
mfa_serial = arn:aws:iam::「IAMユーザ用アカウントのID」:mfa/user-dev01
role_session_name = user-dev01
source_profile = blue21-iam

~/.aws/credentiales は下記のとおり。
[blue21-iam]
aws_access_key_id = 「アクセスキー」
aws_secret_access_key = 「シークレットアクセスキー」

「IAM用アカウント」で作業したい場合は、下記のように実行します。
MFAの認証コードを聞かれるので、認証コードを入力すると実行できます。
$ aws s3 ls --profile blue21-dev
Enter MFA code for arn:aws:iam::123456789012:mfa/user-dev01:

「開発用アカウント」で作業したい場合は、下記のように実行します。
MFAの認証コードを聞かれるので、認証コードを入力すると実行できます。
$ aws s3 ls --profile sandbox-dev
Enter MFA code for arn:aws:iam::345678901234:mfa/user-dev01:

aws-cliでMFAする場合は、aws-mfaを使うと便利です。
下記ページ参照




2021年6月15日火曜日

emacs の neotree の色を変える


emacs に neotree をいれてみました。 

環境は以下のとおり。

  • Windows10 + WSL2
  • ubuntu20.04
  • emacs 26.3


init.el の設定は以下のとおり。

(require 'neotree)
(setq neo-theme 'acsii)
(setq neo-persist-show t)
(setq neo-smart-open t)
(global-set-key "\C-o" 'neotree-toggle)


これで、Ctlキー+oキーでディレクトリ一覧が表示されます。

下図はWindowsターミナルの表示例ですが、ファイル名の表示色が黒なので背景に同化して見えません。(赤枠の部分)



neotreeの色を変えてみます。

init.el に custom-set-fasesの設定を追加します。

(require 'neotree)
(setq neo-theme 'acsii)
(setq neo-persist-show t)
(setq neo-smart-open t)
(global-set-key "\C-o" 'neotree-toggle)
(custom-set-faces
 '(neo-root-dir-face ((t (:foreground "#8D8D84"))))
 '(neo-dir-link-face ((t (:foreground "#0000FF"))))
 '(neo-file-link-face ((t (:foreground "#BA36A5")))))


下図のようにファイル名が見えるようになりました。










2021年5月23日日曜日

localstack と一緒に使うと便利なもの


下記は、localstack用の docker-compose.yml

localstakのGitHUBページにあります。

version: '2.1'

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME-localstack_main}"
    image: localstack/localstack
    ports:
      - "4566-4599:4566-4599"
      - "${PORT_WEB_UI-8080}:${PORT_WEB_UI-8080}"
    environment:
      - SERVICES=${SERVICES- }
      - DEBUG=${DEBUG- }
      - DATA_DIR=${DATA_DIR- }
      - PORT_WEB_UI=${PORT_WEB_UI- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- }
      - DOCKER_HOST=unix:///var/run/docker.sock
      - HOST_TMP_FOLDER=${TMPDIR}
    volumes:
      - "${TMPDIR:-/tmp/localstack}:/tmp/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"


下記は、localtack を使うときに参考にするページ

 

localstack のGitHUBページ


localstack用のaws-cliラッパー(awslocalコマンド)
localstak用のsam-cliラッパー(samlocalコマンド)
localstack用のserverless framework プラグイン

aws-cliのプラグイン
configファイルにエンドポイントを設定できる。


    2021年5月15日土曜日

    bloggerにアクセスしたら赤い画面が、、


    今日、ブログの記事を書こうと思って、 

    Chrome で Blogger にアクセスしたら、下図のメッセージが表示された。




    「何これ???!!」と思ったが、しばらく放置。。。


    1時間後にアクセスしたら、赤い画面は表示されなくなりました。


    Chromeに、

    「こんな機能、あったんだ・・・」と、

    勉強させてもらいました。




    2021年4月29日木曜日

    CDK(TypeScript)で自分好みのVPCを作りたい

     

    cdk で下記のようすると、1行でベストプラクティスのvpcを作ってくれます。

    this.vpc = new ec2.Vpc(this, "TheVpc", cidr="10.0.0.0/16");

    PublicSubnet,PrivateSubnet,IGW,Natgatewayなどが作られますが、

    ちょっと検証したいだけの場合は、大げさすぎます。

    NatGatewayは料金が高いし、あまり、使いたくありません。

    自分好みのVPCを作りたい場合は、subnetConfigurationを空にします。

    this.vpc = new ec2.Vpc(this, 'TheVPC', {
    cidr: "10.0.0.0/16",
    defaultInstanceTenancy: ec2.DefaultInstanceTenancy.DEFAULT,
    enableDnsSupport: true,
    enableDnsHostnames: true,
    subnetConfiguration: []
    });

    PublicSubnet、PrivateSubnet、IGWだけにして、他のスタックでVpcID, SubnetIDを使用できるようにしたいと思ったら、

    最終的に、以下のようになりました。

    import * as ec2 from '@aws-cdk/aws-ec2';
    import * as cdk from '@aws-cdk/core';
    
    export class VpcStack extends cdk.Stack {
        vpc: ec2.IVpc;
        pubSubnet: ec2.ISubnet[] = new Array(2);
        priSubnet: ec2.ISubnet[] = new Array(2);
    
        constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
            super(scope, id, props);
    
            // resources
    
            const internetGateway = new ec2.CfnInternetGateway(this, "InternetGateway", {})
    
            this.vpc = new ec2.Vpc(this, 'TheVPC', {
                cidr: "10.0.0.0/16",
                defaultInstanceTenancy: ec2.DefaultInstanceTenancy.DEFAULT,
                enableDnsSupport: true,
                enableDnsHostnames: true,
                subnetConfiguration: []
            });
    
            const pub1 = new ec2.Subnet(this, "PublicSubnet1a", {
                availabilityZone: "us-east-1a",
                vpcId: this.vpc.vpcId,
                cidrBlock: "10.0.0.0/24"
            });
            pub1.addRoute("PubSubnetRoute", {
                routerType: ec2.RouterType.GATEWAY,
                routerId: internetGateway.ref
            });
            this.pubSubnet[0] = pub1
    
            const pub2 = new ec2.Subnet(this, "PublicSubnet1c", {
                availabilityZone: "us-east-1c",
                vpcId: this.vpc.vpcId,
                cidrBlock: "10.0.1.0/24"
            });
            pub2.addRoute("PubSubnetRoute", {
                routerType: ec2.RouterType.GATEWAY,
                routerId: internetGateway.ref
            });
            this.pubSubnet[1] = pub2
    
            this.priSubnet[0] =  new ec2.Subnet(this, "PrivateSubnet1a", {
                availabilityZone: "us-east-1a",
                vpcId: this.vpc.vpcId,
                cidrBlock: "10.0.10.0/24"
            });
    
            this.priSubnet[1] = new ec2.Subnet(this, "PrivateSubnet1c", {
                availabilityZone: "us-east-1c",
                vpcId: this.vpc.vpcId,
                cidrBlock: "10.0.11.0/24"
            });
    
            new ec2.CfnVPCGatewayAttachment(this, "gateway", {
                vpcId: this.vpc.vpcId,
                internetGatewayId: internetGateway.ref
            });
    
            // outputs
    
            new cdk.CfnOutput(this, 'VpcId', {
                description: 'vpc id',
                value: this.vpc.vpcId,
                exportName: `${this.stackName}-vpcId`
            });
    
            new cdk.CfnOutput(this, 'PublicSubnetId1', {
                description: 'public subnet id (a)',
                value: this.pubSubnet[0].subnetId,
                exportName: `${this.stackName}-publicSubnetId1`
            });
    
            new cdk.CfnOutput(this, 'PublicSubnetId2', {
                description: 'public subnet id (c)',
                value: this.pubSubnet[1].subnetId,
                exportName: `${this.stackName}-publicSubnetId2`
            });
    
            new cdk.CfnOutput(this, 'PrivateSubnetId1', {
                description: 'private subnet id (a)',
                value: this.priSubnet[0].subnetId,
                exportName: `${this.stackName}-privateSubnetId1`
            });
    
            new cdk.CfnOutput(this, 'PrivateSubnetId2', {
                description: 'private subnet id (c)',
                value: this.priSubnet[1].subnetId,
                exportName: `${this.stackName}-privateSubnetId2`
            });
        }
    }


    low-levelのCfnVPCを使う方法は、下記ページが詳しいです。


    Constructの種類(high-level, low-level,pattern)については、下記ページが詳しいです。





    2021年3月21日日曜日

    AmazonEcs ExecでFargateコンテナに入る

     

    ECSのFargateコンテナに入ることができるようになりました。

    詳しくは、下記のAWSブログを参照。


    CloudFormationでECSを構築して試してみました。


    環境


    cfnテンプレート


    • VPC、ECS、Fargateを構築します。
    • AWS::ECS::ServiceのEnableExecuteCommandを trueにすると Fargateに入れるようになります。
    • 今回は nginx コンテナを1つ起動します。

    AWSTemplateFormatVersion: "2010-09-09"
    
    Description: VPC,ECS
    
    Parameters:
      VpcCidr:
        Description: VPC CIDR
        Type: String
        Default: 10.0.0.0/16
    
      SubnetPublicCidr:
        Description: Subnet CIDR. (public)
        Type: String
        Default: 10.0.0.0/24
    
    Resources:
      MyVPC:
        Type: AWS::EC2::VPC
        Properties:
          CidrBlock: !Sub ${VpcCidr}
          EnableDnsSupport: true
          EnableDnsHostnames: true
          InstanceTenancy: default
    
      RouteTablePublic:
        Type: AWS::EC2::RouteTable
        Properties:
          VpcId: !Ref MyVPC
    
      SubnetPublic:
        Type: AWS::EC2::Subnet
        Properties:
          VpcId: !Ref MyVPC
          CidrBlock: !Sub ${SubnetPublicCidr}
          MapPublicIpOnLaunch: true
          AvailabilityZone: !Select
            - 0
            - !GetAZs ""
    
      SubnetPublicIn1RouteTableAssociation:
        Type: AWS::EC2::SubnetRouteTableAssociation
        Properties:
          SubnetId: !Ref SubnetPublic
          RouteTableId: !Ref RouteTablePublic
    
      InternetGateway:
        Type: AWS::EC2::InternetGateway
    
      AttachGateway:
        Type: AWS::EC2::VPCGatewayAttachment
        Properties:
          VpcId: !Ref MyVPC
          InternetGatewayId: !Ref InternetGateway
    
      RouteIgw:
        Type: AWS::EC2::Route
        Properties:
          RouteTableId: !Ref RouteTablePublic
          DestinationCidrBlock: 0.0.0.0/0
          GatewayId: !Ref InternetGateway
    
      EcsCluster:
        Type: AWS::ECS::Cluster
        Properties:
          ClusterName: !Sub ${AWS::StackName}
          CapacityProviders:
            - FARGATE_SPOT
          DefaultCapacityProviderStrategy:
            - CapacityProvider: FARGATE_SPOT
              Weight: 1
    
      EcsSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
          GroupDescription: ECS Security Group
          VpcId: !Ref MyVPC
          SecurityGroupIngress:
            - CidrIp: 10.0.0.0/16
              FromPort: -1
              IpProtocol: "-1"
              ToPort: -1
    
      EcsService:
        Type: AWS::ECS::Service
        Properties:
          ServiceName: !Sub ${AWS::StackName}
          Cluster: !Ref EcsCluster
          DesiredCount: 1
          EnableExecuteCommand: true
          TaskDefinition: !Ref EcsTaskDefinition
          DeploymentController:
            Type: ECS
          DeploymentConfiguration:
            MaximumPercent: 200
            MinimumHealthyPercent: 100
          NetworkConfiguration:
            AwsvpcConfiguration:
              AssignPublicIp: ENABLED
              SecurityGroups:
                - !Ref EcsSecurityGroup
              Subnets:
                - !Ref SubnetPublic
    
      EcsTaskCloudwatchLogsGroup:
        Type: AWS::Logs::LogGroup
        Properties:
          LogGroupName: !Sub "${AWS::StackName}"
          RetentionInDays: 1
    
      ECSTaskRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub ${AWS::StackName}-task
          AssumeRolePolicyDocument:
            Statement:
              - Effect: Allow
                Principal:
                  Service: [ecs-tasks.amazonaws.com]
                Action: ['sts:AssumeRole']
          Path: /
          ManagedPolicyArns:
            - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
          Policies:
            - PolicyName: ssm
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: Allow
                    Action:
                      - ssmmessages:CreateControlChannel
                      - ssmmessages:CreateDataChannel
                      - ssmmessages:OpenControlChannel
                      - ssmmessages:OpenDataChannel
                    Resource:
                      - '*'
    
      ECSTaskExecRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub ${AWS::StackName}-taskexec
          AssumeRolePolicyDocument:
            Statement:
              - Effect: Allow
                Principal:
                  Service: [ecs-tasks.amazonaws.com]
                Action: ['sts:AssumeRole']
          Path: /
          ManagedPolicyArns:
            - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
    
      EcsTaskDefinition:
        Type: AWS::ECS::TaskDefinition
        Properties:
          Family: !Sub "${AWS::StackName}"
          TaskRoleArn: !GetAtt ECSTaskRole.Arn
          ExecutionRoleArn: !GetAtt ECSTaskExecRole.Arn
          Cpu: "256"
          Memory: "512"
          NetworkMode: awsvpc
          RequiresCompatibilities:
            - FARGATE
          ContainerDefinitions:
            - Name: nginx
              Essential: true
              Image: nginx
              LogConfiguration:
                LogDriver: awslogs
                Options:
                  awslogs-group: !Ref EcsTaskCloudwatchLogsGroup
                  awslogs-region: !Sub ${AWS::Region}
                  awslogs-stream-prefix: nginx
              PortMappings:
                - HostPort: 80
                  ContainerPort: 80


    Makefile


    • 検証で使用するコマンドをMakefileに記述します。
    • 下記サンプルではTABがスペース8個に置き換わっているので注意。(そのままコピペしても動きません。)
    • cfn-python-lintについては下記URL参照
      https://github.com/aws-cloudformation/cfn-python-lint

    #-----------------------------------------------------
    # valiables
    #-----------------------------------------------------
    AWSPROFILE := blue21
    
    #-----------------------------------------------------
    # validate cfn template
    #-----------------------------------------------------
    
    all: lint
    lint:
            docker run --rm -v `pwd`:/data cfn-python-lint /data/cfn_*.yml
    
    #-----------------------------------------------------
    # deploy
    #-----------------------------------------------------
    
    deploy:
            $(eval STACK_NAME := Blue21EcsPoC)
            rain deploy cfn_ecs.yml $(STACK_NAME) $(RAINOPT) \
            --profile $(AWSPROFILE) \
            --params \
            VpcCidr=10.0.0.0/16,\
            SubnetPublicCidr=10.0.0.0/24
    
    #-----------------------------------------------------
    # stack
    #-----------------------------------------------------
    
    # LIST Stack
    stackls:
            aws cloudformation describe-stacks \
            --profile $(AWSPROFILE) \
            --query 'Stacks[?contains(StackName,`Blue21`)].{StackName:StackName,StackStatus:StackStatus,Desc:Description}' \
            --output table
    
    # DELETE Stack
    stackrm:
            rain rm $(STACK_NAME) \
            --profile $(AWSPROFILE)
    
    #-----------------------------------------------------
    # util
    #-----------------------------------------------------
    
    update_svc:
            $(eval CLUSTER_NAME := Blue21EcsPoC)
            $(eval SERVICE_NAME := Blue21EcsPoC)
            aws ecs update-service --cluster $(CLUSTER_NAME) --service $(SERVICE_NAME) --enable-execute-command --profile $(AWSPROFILE)
    
    list_task:
            $(eval CLUSTER_NAME := Blue21EcsPoC)
            $(eval SERVICE_NAME := Blue21EcsPoC)
            aws ecs list-tasks --cluster $(CLUSTER_NAME) --service-name $(SERVICE_NAME) --profile $(AWSPROFILE)
    
    describe_task:
            $(eval CLUSTER_NAME := Blue21EcsPoC)
            aws ecs describe-tasks --cluster $(CLUSTER_NAME) --tasks $(TASK) --profile $(AWSPROFILE)
    
    exec_task:
            $(eval CLUSTER_NAME := Blue21EcsPoC)
            aws ecs execute-command --cluster $(CLUSTER_NAME) --task $(TASK) --container nginx --command "/bin/bash" --interactive --profile $(AWSPROFILE)


    ファイルの配置


    cfnテンプレート(cfn_ecs.yml)とMakefileは、下記のようにファイルを配置します。

    $ tree .
    .
    ├── Makefile
    └── cfn_ecs.yml
    
    0 directories, 2 files


    動作確認

     

    cfn-python-lintでcfnテンプレートをテストします。

    下記のようにcfn-python-lint が、まだ、EnableExecuteCommandに対応してないようなのでエラーになりますが、無視します。

    $ make lint
    docker run --rm -v `pwd`:/data cfn-python-lint /data/cfn_*.yml
    E3002 Invalid Property Resources/EcsService/Properties/EnableExecuteCommand
    /data/cfn_ecs.yml:88:7
    
    make: *** [Makefile:22: lint] Error 2


    Rainでスタックを作成します。

    $ make deploy

    下図は実行例です。


    スタックを確認します。

    $ make stackls
    下図は実行例です。

    タスク一覧を表示します。
    arn の最後の部分(3d5562a63bb94749a67048002f2995bf)を、あとで、使用します。
    $ make list_task
    aws ecs list-tasks --cluster Blue21EcsPoC --service-name Blue21EcsPoC --profile blue21
    {
        "taskArns": [
            "arn:aws:ecs:us-east-1:0123456789:task/Blue21EcsPoC/3d5562a63bb94749a67048002f2995bf"
        ]
    }

    タスクの詳細を表示します。
    platformVersionが1.4.0で、enableExecuteCommand が true であれば、Fargateに入れます。

     make describe_task TASK=3d5562a63bb94749a67048002f2995bf
    aws ecs describe-tasks --cluster Blue21EcsPoC --tasks 3d5562a63bb94749a67048002f2995bf --profile blue21
    {
        "tasks": [
            {
                "attachments": [
                    {
    ~省略~
                "desiredStatus": "RUNNING",
                "enableExecuteCommand": true,
                "group": "service:Blue21EcsPoC",
    
    ~省略~
                "platformVersion": "1.4.0",
    ~省略~

    Fargateタスクに入ります。

    $ make exec_task TASK=3d5562a63bb94749a67048002f2995bf

    下図は実行例です


    Fargateコンテナで実行したコマンドはCloudWatchLogsに記録されます。




    あとかたずけ


    CloudFormationで構築した環境を削除します。

    $ make stackrm STACK_NAME=Blue21EcsPoC

    下図は実行例です。






    2021年3月12日金曜日

    Vagrant上のDockerコンテナをホストオンリーネットワークに接続してみる


    環境


    • Windows10
    • WSL2(ubuntu20.04)
    • Windows版VirtualBox6.1.18
    • Windows版vagrant2.2.14

    Vagrant 起動


    ubuntu20.04をvagrantで起動します。
    Vagrantfile は下記のとおり。
    VirtualBoxのホストオンリーネットワークが、192.168.56.0/24 であることが前提です。
    仮想マシンには 192.168.56.10の固定IPアドレスを割り当てます。

    Vagrant.configure("2") do |config|
    
      config.vm.box = "bento/ubuntu-20.04"
      config.vm.network "private_network", ip: "192.168.56.10", auto_config: false
    
      config.vm.provider "virtualbox" do |vb|
        vb.memory = "2048"
        vb.name = 'ubuntu20'
        vb.cpus = 2
        vb.customize ['modifyvm', :id, '--nicpromisc2', 'allow-all']
      end
    
      # https://www.vagrantup.com/docs/synced-folders/nfs
      #config.vm.synced_folder ".", "/vagrant", type: "nfs"
    
      config.vm.provision "shell", inline: <<-SHELL
        apt update
    
        # japanese
        apt install language-pack-ja-base language-pack-ja -y
        localectl set-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja"
        timedatectl set-timezone Asia/Tokyo
    
        # docker
        apt install apt-transport-https ca-certificates curl software-properties-common
        curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
        add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
        apt update
        apt install docker-ce -y
        usermod -aG docker vagrant
        curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
        chmod +x /usr/local/bin/docker-compose
    
        # https://qiita.com/sadapon2008/items/b5c83fedcb07de45f74e
        apt install bridge-utils
        ip addr flush dev eth1
        docker network create --driver bridge --subnet=192.168.56.0/24 --gateway=192.168.56.10 --opt "com.docker.network.bridge.name"="docker1" my_bridge
        mkdir -p /etc/systemd/system/docker.service.d
        echo '[Service]' > /etc/systemd/system/docker.service.d/override2.conf
        echo 'ExecStartPost=/bin/sh -c "/usr/bin/sleep 1s; /usr/sbin/ip addr flush dev eth1; /usr/sbin/brctl addif docker1 eth1; ip link set eth1 up"' >> /etc/systemd/system/docker.service.d/override2.conf
        echo 'ExecStopPost=/bin/sh -c "/usr/sbin/brctl delif docker1 eth1"' >> /etc/systemd/system/docker.service.d/override2.conf
        systemctl daemon-reload
        systemctl restart docker
        brctl show
        ip a | grep eth1 -A 5
     SHELL
    end

    "vagrant up"コマンドで起動します。
    初回起動中にdocker をインストールしてネットワーク関連の設定を行います。
    起動に成功すると、ネットワーク関連の情報が、下記のように表示されます。

        default: bridge name        bridge id               STP enabled     interfaces
        default: docker0            8000.024207e2ad64       no
        default: docker1            8000.024282583d53       no              eth1
        default: 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master docker1 state UP group default qlen 1000
        default:     link/ether 08:00:27:cd:6b:9f brd ff:ff:ff:ff:ff:ff
        default:     inet6 fe80::a00:27ff:fecd:6b9f/64 scope link tentative
        default:        valid_lft forever preferred_lft forever
        default: 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
        default:     link/ether 02:42:07:e2:ad:64 brd ff:ff:ff:ff:ff:ff

    動作確認


    "vagrant ssh"コマンドで仮想マシンに入ります。
    下記の内容で、docker-compose.yml を作成します。
    コンテナには、ホストオンリーネットワークの固定IPドレスを割り当てます。
    ついでに、各コンテナの/etc/hosts にFQDNも設定します。

    version: '3'
    services:
    
      nginx00:
        image: nginx
        container_name: nginx00
        hostname: nginx00
        networks:
          default:
            ipv4_address: 192.168.56.11
        extra_hosts:
          - nginx00.local:192.168.56.11
          - nginx01.local:192.168.56.12
    
      nginx01:
        image: nginx
        container_name: nginx01
        hostname: nginx01
        networks:
          default:
            ipv4_address: 192.168.56.12
        extra_hosts:
          - nginx00.local:192.168.56.11
          - nginx01.local:192.168.56.12
    
    networks:
      default:
        external:
          name: my_bridge

    "docker-compose up -d"コマンドで起動します。
    仮想マシン内でnginx00コンテナに固定IPでアクセスできるか確認してみます。
    下図のように表示されたら成功です。


    nginx01コンテナ内からnginx00コンテナにアクセスできるか確認してみます。
    nginx00にアクセスするときは、docker-compose.ymlで定義したFQDN(nginx00.local)でアクセスできるか確認します。
    下図のように表示されたら成功です。


    最後にWSL2のターミナル内から仮想マシン上のDockerコンテナに固定IPでアクセスできるか確認します。
    下図のように表示されたら成功です。


    ちなみに、
    Windowsのブラウザでも仮想マシン上のコンテナに固定IPでアクセスできます。



    WSL2の /etc/hosts に nginx00.local, nginx01.local を設定すれば、WSL2からFQDNでアクセスできるようになります。


    2021年1月17日日曜日

    aws-cliでAWSコンソールのログイン履歴を調べる

     

    下記は、CloudTrailからAWSコンソールのログイン履歴を取得するaws-cliのコマンドです。

    aws cloudtrail lookup-events \
    --max-items 20 \
    --lookup-attributes "AttributeKey=EventName,AttributeValue=ConsoleLogin" \
    --query Events[].CloudTrailEvent --output text \
    | tr "\t" "\n" \
    | jq -r '.|[.eventTime,.eventType,.userIdentity.userName,.sourceIPAddress,.userAgent,.responseElements.ConsoleLogin,.additionalEventData.MFAUsed]|@csv'


    このコマンドの実行結果(CSV)を、JupyterLab で見たいので以下のようにしてセルに記述してみます。

    import io
    import pandas as pd
    data = !aws cloudtrail lookup-events \
    --max-items 20 \
    --lookup-attributes "AttributeKey=EventName,AttributeValue=ConsoleLogin" \
    --query Events[].CloudTrailEvent --output text \
    | tr "\t" "\n" \
    | jq -r '.|[.eventTime,.eventType,.userIdentity.userName,.sourceIPAddress,.userAgent,.responseElements.ConsoleLogin,.additionalEventData.MFAUsed]|@csv'
    df = pd.read_csv(
        io.StringIO(data.n),
        header=None,
        names=["EventTime", "EventType", "UserName", "SourceIP", "UserAgent", "Response", "MFAUsed"])
    print("作成日: ",end="")
    !date
    df


    下図は、JupyterLabの画面表示例です。