Re:Invent2019で発表されていたAWS CLI V2 について触ってみました

クラウド事業部の原口です。
今年は初めて AWS Re:Invent に参加する事ができました。
いろいろ書きたい事はあるのですがクリエイターズブログなのか?という事もあり、技術的なネタで、本日はAWS CLI v2 を触ってみたという内容となります。

ちなみにコネクションハブの OVERFLOW 枠で参加してました

AWS CLI v2の新機能をレビュー

インストール

インストールにpythonが必要がなくなり非常に簡単になりました!
MacOSやWindowsではインストーラーポチでよいようです。
ひとまずはAmazon Linuxにインストールしてみました

cd /usr/local/src
curl "https://d1vvhvl2y92vvt.cloudfront.net/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

現在はプレビューという事もあり aws2 というコマンドが追加されていてv1のawsコマンドと共存が可能なようです

設定が対話式で行えるようになりました

aws2 configure wizard というコマンドが追加され対話式で設定が可能となっていました

こういった対話式で設定を行うものは多数増やしていく、との事。対話式で行えるのはawsコマンドの設定だけではなく、各種コマンドについても増やしていく、との事。
例えばDynamoDBでテーブルを作る時は一生懸命ドキュメントを見ながら設定していましたが…

このように `aws2 dynamodb wizard new-table` とする事で対話式で新規テーブル作成が可能でした。便利

コマンド補完がすごくなっている

complete -C aws2_completer aws2

こちらでタブ補完を有効化したのちに以下のようにタブで補完される事が確認できました。こちらがアップデートされて、各種コマンドの引数はもちろんの事、なんとそのリソースの補完も行えるようになりました。
先程つくったdynamoDBのtestというテーブルを削除したい場合の動きです。

[root@ip-10-0-0-134 ~]# aws2 dynamodb delete-
delete-backup  delete-item    delete-table   

[root@ip-10-0-0-134 ~]# aws2 dynamodb delete-table --ta<TAB>
↓
[root@ip-10-0-0-134 ~]# aws2 dynamodb delete-table --table-name <TAB>
↓
[root@ip-10-0-0-134 ~]# aws2 dynamodb delete-table --table-name test 

わざわざ実際のリソースをlistで一覧してから確認したりする必要がないです!とてもすごいと思いました

AWS SSOとの連携

AWS CLI v2だけの機能としてAWS SSOとの連携が可能なようで試してみました。
AWS SSOについては「AWS SSOを使って複数AWSアカウントのログインを簡単にする!」で試してみましたのでこの環境にログインしてみたいと思います。

まずはaws2 configure sso コマンドでssoの設定を行います。
といっても SSOのstartページとSSOを設定しているリージョンを設定するだけです。

すると
https://device.sso.us-east-1.amazonaws.com/
へのアクセスをアクセスして、出力されているcodeを入力せよ、となります。

ここでブラウザで上記URLに接続するとcodeを記述する画面が出てきます。

CLI側で出力されているコードを入力し、ログインすると、「CLIでログインするか?」というポップアップが出てくるのでSignします。

するとCLI側はsingした瞬間にずらずらと動きだし、ログインできるAWSアカウントが一覧されます。こちらもインタラクティブモードで選択可能です。

ここでアカウントを選択すると、そのaws2コマンドはもうそのAWSアカウントの世界になっています。
一旦ブラウザを挟んでログインするとCLI側が動く、というのは新鮮でしたが、SSOログインと連携する事で余計なAWSシークレットキー/アクセスキーを出力する機会を減らせるかもしれないですね。

その他の追加項目

以下はさらっと試したレベルですが以下の内容が新規に追加されているようです

・出力にyamlが追加された
・Paging機能の追加。

正式発表が楽しみですね!

AWS SSOを使って複数AWSアカウントのログインを簡単にする!

クラウド事業部の原口です。

皆様は複数あるAWSアカウントの管理、どのように管理されているでしょうか?
一般的にある1つのサービスに対して以下のように環境に応じたアカウントを用意する事が多いのではないでしょうか。

「本番環境用アカウント」
「ステージング環境用アカウント」
「テスト環境用アカウント」

このように複数の環境を作ってくると問題となってくるのがログインにかかるコストになります。
MFAなどの設定をしていったり…といった事をすべての環境ぶん行う必要があったり、新しい人がジョインした、プロジェクトを抜けた、というたびにすべての環境のIAM設定が必要。またそれぞれの権限の範囲など…となってくると本当にバカにできないコストとなってきます。

これまで複数AWSアカウントの管理といえばIAMのスイッチロールを使うという方法がとられてきましたが、
今回、AWS SSOがMicrosoft AD以外も選択できるようになった、、具体的にはAWS SSO の ID ストアでユーザー ID を作成および管理ができるようになった、という事を知り、スイッチロールの代替になるのでは!?という事で検証してみました。
もう一度繰り返しますと ADが不要でAWS SSOの機能だけで利用可能となってました。
しかも無料なんですよね。すごい。

AWS SSOを利用する

0.AWS SSOに必要な環境

・AWS SSOを設定するアカウントがAWS Organizationを利用しており、その親アカウントである事
・バージニアリージョンでのみ利用可能(ですが特に問題はないかと)

①AWS SSOを有効化

まずはリージョンをバージニアに変更して AWS Single Sign-Onのページへ移動し、「AWS SSOを有効にする」をクリックします。
これだけで AWS SSO の ID ストアでユーザー ID を作成および管理ができる状態でセットアップされます

② ID ストアでユーザー ID を作成

IDソースを選択、もしくは左メニューのユーザをクリックして新規にユーザを登録します。
ユーザはパスワード認証の他にもMFA認証も対応していますので安心ですね。
ユーザ作成すると作成時に設定したメールアドレスに招待メールが送られますのでAcceptしてください。

③AWS アカウントでOrganizationに属するアカウントに対してユーザとログイン権限と認証の設定を行う

AWS アカウントを選択すると AWS Organizationで属している組織のアカウントがすべて表示されます。これらの中でログインさせたいアカウントをチェックし「ユーザの割り当て」を行います。ここで先程のIDプールで作成したユーザが一覧として出てきます。

ユーザーの設定を行ったあとは、該当組織の子アカウントに対するアクセス権限セットを設定します。IAMポリシーとほぼ同じようなイメージとなります。
これらはアカウント毎(グループ毎)に設定できる為、きめ細かな権限設定が可能です。
ちなみにここでポリシーを設定すると子アカウント側にはそのIAMロールが作られる形でした。
つまり内部的な技術仕様としてはスイッチロールを使用しているのとほぼ変わらない動きとなっているようです。
ちなみにこのIAMロールは子アカウントのrootアカウントでも削除はできませんでした。 また、cloudtrailではIDプールで設定したユーザ名で記録されていました。(完璧!)

④作成したユーザでログインする

SSOを作成した際に同時に作成されるユーザポータルよりログインします。
https://xxxxxxx.awsapps.com/start のものですね。
xxxxxxxの部分はカスタマイズ可能ですが変更は1度しかできないようですのできちんと意味のある名前にしたほうがよいです。
上記のURLにログインするとログイン画面が出てきます

ログインするとこんな形で設定したアカウントが一覧で表示されます。アタッチしている権限で Management console をクリックするとその権限でアカウントにログインできました!

感想

AWS SSO自身がIDプールを持つ事ができるようになったおかげで、Microsoft ADを使用せずとも気軽に複数アカウントへのログインが可能となりました。
内容としてはスイッチロールと大きく変わらないようなので、「スイッチロールの設定が簡単にできるようになった」と捉えて、スイッチロールの代替として使ってみてもいいのではないかと思います。
以下はAWS公式ブログより転載している画像ですがこれをきっかけに複数の他アプリへのログインやカスタムSAMLのアプリケーションへのSSOログインが可能です

まずは簡単にAWSアカウントの管理から初めてみて、今後組織のユーザのslackなどのアプリケーションもすべてこちらでログイン管理してしまうと大変便利になっていくのではないかという可能性を感じました。
AWS CLI v2 ではこのAWS SSOに対応しているという事でそのあたりもとても便利になりそうに思います。

現時点での不満点としては以下となります
・AWS Organizationが必須なので請求を一緒にできないアカウントでは厳しい
・スイッチしたロール名を変えれないので地味にどの環境にログインしているかわからなくなる

前半は仕方がないように思いますが、ログイン後のアカウントがどのAWSアカウントであるかはすぐにわかるようになると嬉しいな、、、と感じました。

IAMユーザを使ってEC2のLinuxユーザを管理する

クラウドソリューション事業部 インフラエンジニアの上野です。

皆さんはEC2(Linux)のユーザ管理をどのようにされていますか?
個別の管理シートのようなものを用意して管理をされていたりするのでしょうか?あるいはディレクトリサービスと連携させて管理しているのでしょうか?

人の出入りが激しいプロジェクトや、そもそもの管理するインスタンス数が多い場合に 個別にユーザを作成・削除したり、現在のユーザの状況を管理するのは非常に運用コストがかかります。

このようなユーザ作成・削除の運用コストやユーザの管理の問題を解決するのにおすすめのaws-ec2-sshというツールを紹介します。

aws-ec2-ssh
https://github.com/widdix/aws-ec2-ssh

aws-ec2-sshはIAMユーザとEC2のLinuxユーザを紐付けし、IAMユーザの作成・削除に連動して、Linuxユーザも作成・削除されるという便利ツールです。

それでは早速導入していきましょう。

aws-ec2-sshの導入方法(AWS側)

まずはAWS側の設定を行います。
EC2インスタンスがaws-ec2-sshを使えるようにするためのIAMロールを用意します。 下記のポリシーを持つIAMロールを作成し、連携を行うEC2インスタンスにロールを割り当てます。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "iam:ListUsers",
      "iam:GetGroup"
    ],
    "Resource": "*"
  }, {
    "Effect": "Allow",
    "Action": [
      "iam:GetSSHPublicKey",
      "iam:ListSSHPublicKeys"
    ],
    "Resource": [
      "arn:aws:iam::<YOUR_USERS_ACCOUNT_ID_HERE>:user/*"
    ]
  }, {
      "Effect": "Allow",
      "Action": "ec2:DescribeTags",
      "Resource": "*"
  }]
}

※<YOUR_USERS_ACCOUNT_ID_HERE>にはAWSのアカウントIDを記入してください。

次にIAMグループを作成します。
ここで作成したグループを元に連携させるIAMユーザであるか、連携させるIAMユーザは管理者権限を付与する対象であるかを判別します。
今回は linux-member を連携対象とするグループ、linux-adminを特権ユーザとするグループとします。

  • linux-member( 連携対象とするグループ )
  • linux-admin(特権ユーザ用のグループ )

それでは連携させるIAMユーザを作成します。
今回はテストのために、次の3つのユーザを登録します。

  • user-member
    Linuxの一般ユーザとして登録するユーザ
    linux-member のIAMグループに 所属
  • user-admin
    Linuxの管理者ユーザとして登録するユーザ
    linux-memberとlinux-admin のIAMグループに 所属
  • no-linux-user
    Linuxには同期させないユーザ
    いずれのIAMグループにも所属しない

IAMユーザ作成後に
IAM > ユーザ > 対象のユーザ > 認証情報 > SSHパブリックキーのアップロード
から公開鍵認証用の公開鍵をアップロードします。

作成したIAMユーザとグループの状況はこのような形です。

aws-ec2-sshの導入方法(Linuxサーバ側)

ここからはLinuxサーバ側の作業になります。
まずはLinuxサーバにaws-ec2-sshをインストールします。

cd /usr/local/src
git clone https://github.com/widdix/aws-ec2-ssh.git
cd aws-ec2-ssh
./install.sh

aws-ec2-sshの設定ファイルを作成します。

cd /usr/local/src/aws-ec2-ssh
cp aws-ec2-ssh.conf aws-ec2-ssh.conf
vi aws-ec2-ssh.conf

aws-ec2-ssh.confの内容は以下のように設定します。

IAM_AUTHORIZED_GROUPS="linux-member" #管理対象するIAMグループ
LOCAL_MARKER_GROUP="iam-synced-users" #IAMユーザと連携していることを示すグループ
LOCAL_GROUPS=""
SUDOERS_GROUPS="linux-admin" #特権を付与するIAMグループ
ASSUMEROLE=""
# Remove or set to 0 if you are done with configuration
# To change the interval of the sync change the file
# /etc/cron.d/import_users
DONOTSYNC=0 #0の場合に同期機能が有効化

一通り設定ができたので、手動でIAMユーザと連携を行います。
なお、インストール時点で同期処理がcronに登録されており、デフォルトでは10分毎に同期されるように設定されています。

sh /opt/import_users.sh

実行後にユーザが作成されていることが確認できます。
同期対象外であったno-linux-userはLinux上にはユーザを作られていません。

# egrep "user-member|user-admin|no-linux-user" /etc/passwd
user-admin:x:1004:1005::/home/user-admin:/bin/bash
user-member:x:1005:1006::/home/user-member:/bin/bash

user-adminにはsudoの実行権限があります。

# ls /etc/sudoers.d/
90-cloud-init-users  user-admin
# cat /etc/sudoers.d/user-admin
user-admin ALL=(ALL) NOPASSWD:ALL

結果はこのようになりました。

  • Linux上にuser-adminとuser-memberというユーザが追加された
  • user-adminには管理者権限が付与されていた
  • 同期対象外のno-linux-userはLinux上にユーザは作成されなかった

意図したとおりに動作していますね。
今回は作成を試しましたが、IAMユーザから削除を行うと、Linuxサーバ上のアカウントも削除されます。

aws-ec2-ssh の仕組み

ここからはaws-ec2-sshの仕組みについて少し説明します。

Q.ユーザをどのように判別しているか?
/etc/aws-ec2-ssh.conf 内の設定をもとに判断して処理しています。

  • IAM_AUTHORIZED_GROUPS
    IAM上でこのグループに所属しているユーザがLinuxサーバへの同期の対象となります。
  • SUDOERS_GROUPS
    IAM上でこのグループに所属しているユーザが管理者権限(sudoの実行権限)を付与されます。
    同期の対象となるにはIAM_AUTHORIZED_GROUPSに指定されたグループに所属している必要があり、 このグループだけに所属している場合はLinuxサーバへの同期対象にはなりません。
  • LOCAL_MARKER_GROUP
    Linuxサーバ上でIAMと同期しているユーザを判別するためのグループです。 このグループに所属しているLinuxサーバ上のユーザがIAMユーザとの同期対象になります。


Q. 同期処理はいつ・どのように実施されるか?
インストール時に/etc/cron.d/import_usersが追加されます。
このcronの設定により10分おきに同期処理が実行されます。
インストール直後からcronが動き出してしまうので注意が必要です。

SHELL=/bin/bash
PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin
MAILTO=root
HOME=/
*/10 * * * * root /opt/import_users.sh

Q. 公開鍵認証はどのように行われているのか?
aws-ec2-sshをインストールすると /etc/ssh/sshd_config に下記の設定が追加されます。

AuthorizedKeysCommand /opt/authorized_keys_command.sh

この設定によりsshで接続時に /opt/authorized_keys_command.sh の実行結果を公開鍵として渡されています。
authorized_keys_command.shではaws cliのコマンドを発行し、対象ユーザと一致するIAMユーザに登録されている公開鍵の情報を取得しています。
この仕組みによりEC2インスタンス上に各ユーザの公開鍵を設置せずに公開鍵認証ができます。

さいごに

いかがでしたでしょうか。

AIMユーザを作成するだけで対象のLinuxサーバに自動的にユーザが追加され、ユーザの公開鍵をサーバに設置するなどの手間も省けます。

また、ユーザ作成時は厳密な手続きのもと作成を行われますが、 作成されたユーザに関しては厳密に管理が行われていないということもあります。
よくある見られるのは利用されていないユーザが削除されずに残っているというパターンです。 削除手続きが正しく行われていない場合もあれば、対象サーバが多く漏れていたということも考えられます。

このような問題を解決してくれる非常に便利なツールでした。
導入も容易なので、ぜひご活用ください。

S3静的ホスティングの次の一歩、https対応をCloudFrontとACMで行う

こんにちは、西山です。
最近、AWS認定ソリューションアーキテクト プロフェッショナルを取得しました!

既に合格したメンバー達が「やってやろうぜ」って雰囲気で挑戦していたのを見て、影響を受けました。人生やったもん勝ちです。

ただ、やはり触って使って身に付けるが基本です。
試験受かっただけのテスト野郎にならないように、今後も手を動かすのを意識して進んでいきます。

今回はS3で静的なサイトを公開した後に、サイトをhttpsに対応する方法を説明してまいります。

この記事の対象者

  • AWSのサービスを使い始めたばかり
  • S3で静的サイトを公開して、次に何か挑戦しようと考えている
  • httpのサイトをhttpsにしたい

■1. 【ACMを使い証明書を取得する】

ACM は AWS Certificate Manager の略です。
SSL/TLS 証明書を管理し、AWSのサイトに簡単に設定する事ができます。

ちなみに、サービス名の英語3文字の略語は、正式名称で覚えた方が混乱せず各AWSのサービス内容を把握できるのでおすすめです。

それでは、ACMの設定に進んでまいりましょう。
まずはAWS マネジメントコンソールでACMの画面を開きます。
「ACM」と入力すれば「Certificate Manager」と表示されますので選択します。

AWS Certificate Manager の画面が開きましたら
まず最初に行う事があります。

注意点

画面右上のリージョン選択で
米国東部 (バージニア北部) us-east-1」を選択してください。
今回はCloudFrontにACMで作成した証明書を関連付ける為です。

その後で、「証明書のプロビジョニング」より「今すぐ始める」をクリックして設定を開始します。

補足

Amazon CloudFront で ACM 証明書を使用するには、米国東部(バージニア北部) リージョンで証明書をリクエストまたはインポートする必要があります。CloudFront ディストリビューションに関連づけられたこのリージョンの ACM 証明書は、このディストリビューションに設定されたすべての地域に分配されます。

https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/acm-regions.html

順番に設定を進めてまいります。
「パブリック証明書のリクエスト」を選択し「証明書のリクエスト」をクリック

ドメイン名の追加の入力箇所に来ました。
今回は静的なサイト http://odenge.jp/ をhttpsに対応する例で説明します。

ドメイン名は下記の2つを設定します。
odenge.jp
*.odenge.jp

※「*.odenge.jp」を設定したのは、今後、test.odenge.jp や sample.odenge.jp などでもhttps対応を考慮する為です。

注意点

「*.odenge.jp」だけでは、「odenge.jp」の設定は反映されないので
「odenge.jp」も記載してください。

以前は「Eメールの検証」のみだったとの事ですが
「Route 53」を使いS3で静的サイトをホスティングしている場合には
簡単に行う事ができる「DNSの検証を」選択します。

補足

DNS検証はRoute 53 でなくても行うことは可能です。

ここは特に何も入力しなくても大丈夫ですので
そのまま「確認」をクリック

確認し「確定とリクエスト」をクリック

「検証保留中」と表示されますが、そのまま「続行」ボタンを押します。

「状況」の「ドメイン」の箇所を開くと
「Route 53でのレコードの作成」ボタンが表示されますのでクリック

下記の情報でRoute 53 にACM設定の為のレコードが追加されます。
「作成」をクリックします。

「検証保留中」とまだ表示されていますが
DNSレコードの追加は成功しました。

「Route 53」で追加されたレコードを確認します。
「Route 53」では右上のリージョンは「グローバル」になります。

再度、「ACM」で右上のリージョンが「米国東部 (バージニア北部) us-east-1」を選択します。
少しだけ待つと「状況」が発行済みとなり証明書が発行されました。
私の場合は数分でしたが、最大で30分以上かかる場合もあるとの事でお待ちください。

これでACMで証明書の取得を行う事ができました。

■2. 【CloudFrontに証明書を設定する】

CloudFrontの画面に行き、右上のリージョンは「グローバル」しかないのでそのまま設定を進んで行き、「Web」の方の「Get Started」をクリック

補足

Q: ACM 証明書は、どの AWS のサービスで使えますか?

パブリックとプライベートの ACM 証明書は、以下の AWS のサービスで使えます。
• Elastic Load Balancing
• Amazon CloudFront
• Amazon API Gateway
• AWS Elastic Beanstalk
• AWS CloudFormation – 現時点では、E メール検証を使うパブリック証明書のみをサポートしています。

「Origin Domain Name」の箇所、手動で入力が必要かと思いましたが
空白にするとプルダウンメニューから選択できるようになり、静的サイトを公開しているS3を選択します。

「Origin Domain Name」と「Origin ID」が自動入力されます。
その他の項目は初期設定のままで下の項目に進みます。

「Alternate Domain Names」に設定するドメインを記載しました。
(www付きでもアクセスできるようにwww付きのドメインも記載しました)

「Custom SSL Certificate」を選択し
先ほどACMで作成した内容がプルダウンメニューで選択できるので選択します。

注意点

「Custom SSL Client Support」は
「Clients that Support Server Name Indication(SNI)」を選択します。
※下の項目を選択すると「$600 / month」と金額がかかってしまいます。

上記に記載した箇所以外は初期設定のまま作成すると
下記の画面のように追加された状態となります。

注意点

作成完了まで30分近くかかりました。結構時間がかかった印象ですので気長に待ちます。「Status」が「Deployed」になれば完成です。

「CloudFront」が「Deployed」になった後
「Route 53」に行き
レコードのタイプ「A」に設定されている「エイリアス先」を「CloudFrontディストリビューション」で作成した内容を選択し、「レコードセットの保存」をクリック

これで https://odenge.jp/ にアクセスすれば完成と考えていましたがエラーが起こりページが表示されませんでした。

「CloudFront」の設定を修正します。
一覧の「ID」に記載されているリンクテキストをクリックし
「Edit」ボタンを押して編集します。

S3の静的ホスティングではトップページをindex.htmlで作成していました。
「Default Root Object」に「index.html」と記載し「Yes, Edit」をクリック

問題なく表示され完成です!
いかがでしたでしょうか?

■3. 【追加のもう一歩 OAI設定】

CloudFrontを使ってアクセスする事ができるようになりましたが
S3のエンドポイントのURLを使っても、現時点ではアクセスできる状態です。

origin access identity(OAI)を使えば、S3に直接アクセスしても閲覧できなくする事が可能です。明確にCloudFrontを通してサイトアクセスを行わせる事を考慮したシステム構成にする事で、CloudFrontによりレイテンシーを低くする事や様々な構成・仕様を考慮した上でシステムを構築する事が可能です。

「CloudFront」の修正方法を見て行きましょう。
作成した内容をチェックし「Distribution Settings」をクリック

タブ「Origins and Origin Groups」を選択し該当の箇所をチェックし
「Edit」をクリック

「Restrict Bucket Access」を「Yes」
「Origin Access Identity」を「Create a New Identity」
「Comment」は自動で記入されるのでそのまま
「Grant Read Permissions on Bucket」を「Yes, Update Bucket Policy」

そして「Yes, Edit」をクリック

修正した「CloudFront」の「Status」が「Deployed」になった後で
S3のバケットポリシーを修正します。

※上記で「Grant Read Permissions on Bucket」を「Yes, Update Bucket Policy」を選択しましたが更新されなかったので直接、S3のバケットポリシーを修正します。

「CloudFront」の「Origin access identity」で下記の図の
「Amazon S3 Canonical User ID」をコピーします。

S3バケットポリシーの「Principal」を変更します。

"Principal":{"CanonicalUser":"コピーした乱数"},

参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies.html#example-bucket-policies-use-case-6

上記の内容で「Principal」の箇所を修正しバケットポリシーを更新しました。すると「Principal」の記載内容が違う記述に書き換わりましたが、それまでアクセスできていたS3エンドポイントのURLからのアクセスが拒否され、CloudFrontからのアクセスのみ許可されている事が確認できました。

あとがき

証明書の設定と聞くと、少し難しい印象を持たれるかもしれません。
しかし、マネジメントコンソールの操作で簡単に設定する事ができます。
ぜひ、試していただければ幸いです。

証明のない現代にドロップキック

以上、西山でした。

LaravelでCakePHP 2.xのfind(‘list’)のようなこと(インデックスつきの配列の取得)をやってみる

こんにちは。CakePHP が好きな小國です。業務では Laravel を触っています。

突然ですが、CakePHP 2.x では Model::find(‘list’) というメソッドがあり、セレクトボックスなどで使うインデックス付きの配列を取得でき重宝していました。

https://book.cakephp.org/2/ja/models/retrieving-your-data.html#find-list

Laravel でも同じようなものがほしいなと思って見ていたのですが、デフォルトの機能にはないようでしたので、作成しましたという内容の記事になります。

やってみます

  • App\Traits\Selectable.php
<?php

namespace App\Traits;

use Illuminate\Database\Eloquent\Model;

trait Selectable
{
    public static function toSelectArray()
    {
        $instance = new static;
        $key = $instance->getKeyName();
        $value = $instance->getDisplayFieldName();

        /** @var Model $this */
        return static::all([$key, $value])
            ->pluck($value, $key)->toArray();
    }

    public function getDisplayFieldName()
    {
        if (property_exists($this, 'displayField')) {
            return $this->displayField;
        }
    }
}

使い方

Selectableトレイを使い、displayFieldプロパティで表示用のカラムを指定します。

<?php

namespace App;

use App\Traits;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use Selectable;

    public $displayField = 'name';
}

toSelectArray() でインデックス付きの配列が取得できます。

User::toSelectArray();

その他

こちらにも同じソースを置いています。https://gist.github.com/tsmsogn/e6d8af0ad182b40ac512eaf1aa4d58fb

新人Webプログラマーとして過ごした2ヶ月半の振り返り

はじめまして!新人webプログラマーの石田ゆかです。

シーズに入社して2ヶ月半が経ちました。
シーズに入社するまでは電機メーカーで回路設計をしていたため、仕事内容も仕事環境も大きく変わりました。

そこで今回はシーズに入社して感じた変化や、この2ヶ月半に新人プログラマーとして取り組んで来たことをご紹介したいと思います。

シーズに入社して感じた変化

シーズに入社して感じた変化はたくさんありますが、会社生活する上で特に負担が減ったと思えることを3つご紹介します。

連絡ツールがslackとチャットワーク

シーズに入社してまず驚いたことが連絡ツールに社内はslack、社外はチャットワークをメインに使っていることです。
メールのように毎回宛先を選んだり挨拶を書く必要がないので、連絡に使う時間が圧倒的に短くなりました。
ちなみに先日久々にメールを使ったところ、ビジネスメールの書き方を忘れていました笑

会議が少ない

会議が少ないため会議の準備や出席に取られる時間が少なく、作業に充てる時間を日々十分に確保出来ています。

出社時間やお昼休憩の時間が自由

出社時間やお昼休憩の時間が自由なため電車の混んでいる時間を避けて出社したり、お店の混んでいる時間を避けてランチが出来ます。

新人プログラマーとして取り組んで来たこと

ツールの使い方を覚える

まずツールが使えないと始まらないということで、ツールの使い方を覚えることから始めました。
PHPStormやbacklogそして本ブログを書いているWordPressなど仕事で使う一通りのツールについて、YouTubeに上がっているチュートリアルを見たりググったりしながら操作を覚えました。

プログラミングスタート

私の所属する印刷事業部では主に既存サイトの保守を行なっているため、既存サイトの機能追加や変更などを行なってきました。
部長直々にサイトやプログラムの仕様、プログラムの流用方法などを教えてもらいながらプログラムの実装を行いました。


今までプロの書いたプログラムに触れたことの無かった私にとって、既存サイトのプログラムを読むことは良い勉強となっています。
また既存プログラムの思想をなるべく丁寧に理解して、私が実装した部分だけ違和感のあるプログラムとならないよう気を付けています。

JavaScript(以下JS)でも苦労

シーズに入社するまでJSを全く勉強していなかったのですが、思っていた以上にサーバーサイドエンジニアでもJSに触れる機会が多く苦労しています。
JSについては同じ印刷事業部の先輩に教えてもらったり、公式ドキュメントを読んだりUdemyの講座を受けながら学習しています。

2ヶ月間の感想とこれからの意気込み

入社して最初の2週間くらいはプログラマーの仕事が難しく気持ちに全く余裕がありませんでしたが、今はほんの少し余裕が持てるようになりました。
まだまだ勉強することだらけ、これから経験していくことだらけですが、1日でも早く一人前のプログラマーになれるよう引き続き頑張っていきたいと思います!

LaravelからS3互換のMinIOを使えるように、docker-compose環境を整える

こんにちは。小國です。最近は Laravel を触っています。

AWS で Laravel アプリケーションを運用する際、ステートレスにするために画像などのファイルを S3 に保管することがあるかと思います。

一方、弊社では Docker を使ってローカルの開発環境を整えており、そこでは S3 の代わりに S3 互換の MinIO を使用しています(使用していこうと思います)。

本記事では、Docker で MinIO の設定、および Laravel から MinIO へファイルの作成・削除・ダウロードをご紹介します。

なお、前提として、すでに Docker(docker-compose)で Laravel アプリケーションが動いているものとします。

環境

  • Laravel 6.1.0

Docker で MinIO を立ち上げる

まずは、docker-compose を使って MinIO を起動します。

  • .env
+# Minio config
+MINIO_PORT=60007
+
+# AWS config
+AWS_URL=http://minio:9000
+AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
+AWS_SECRET_ACCESS_KEY=YYYYYYYYYYYYYYYYYYYY
+AWS_DEFAULT_REGION=us-east-1
+AWS_BUCKET=test
+AWS_PATH_STYLE_ENDPOINT=true
  • docker-compose.yml
+  minio:
+    image: minio/minio 
+    ports:
+      - "${MINIO_PORT}:9000"
+    volumes:
+      - ./.docker/minio/data:/export
+    environment:
+      MINIO_ACCESS_KEY: ${AWS_ACCESS_KEY_ID}
+      MINIO_SECRET_KEY: ${AWS_SECRET_ACCESS_KEY}
+    command: server /export

ホストマシンから MinIO が動いているか確認

docker-compose up -d 後、ホストマシンから http://localhost:60007 につながることを確認します。正しく起動できると以下のような画面が表示されると思います。

f:id:seeds-std:20191108194045p:plain

設定した $AWS_ACCESS_KEY_ID$AWS_SECRET_ACCESS_KEY でログインします。

f:id:seeds-std:20191108192902p:plain

右下の「+」ボタンより、test バケットを作成し(のちほどこのバケットを使用します)、ファイルがアップロードができるか確認しましょう。

Laravel から s3ドライバーで MinIO を使うように変更

s3ドライバー で MinIO を使うよう変更し、Tinker を使って Laravel から保存できることを確認します。

  • flysystem-aws-s3-v3 インストール
$ composer require league/flysystem-aws-s3-v3 ~1.0
  • config/filesystems.php
         's3' => [
             'driver' => 's3',
+            'endpoint' => env('AWS_URL'),
+            'use_path_style_endpoint' => env('AWS_PATH_STYLE_ENDPOINT', false),
             'key' => env('AWS_ACCESS_KEY_ID'),
             'secret' => env('AWS_SECRET_ACCESS_KEY'),
             'region' => env('AWS_DEFAULT_REGION'),
$ php artisan tinker
>>> Storage::disk('s3')->put('hello.json', '{"hello": "world"}')
=> true

MinIO にファイルが作成されているかと思います。

ファイルの作成・削除・ダウロード

Laravel から MinIO へファイルの作成・削除・ダウロードをやってみます。

  • 2019_11_11_020835_create_assets_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAssetsTable extends Migration
{
    public function up()
    {
        Schema::create('assets', function (Blueprint $table) {
            $table->increments('id');
            $table->string('model')->nullable();
            $table->integer('foreign_key')->nullable();
            $table->string('name');
            $table->string('type');
            $table->integer('size');
            $table->string('disk');
            $table->string('path');
            $table->timestamps();
            $table->index(['model', 'foreign_key']);
        });
    }

    public function down()
    {
        Schema::dropIfExists('assets');
    }
}
  • app/Asset.php
<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
class Asset extends Model
{
    protected $fillable = [
        'foreign_key',
        'model',
        'name',
        'type',
        'size',
        'disk',
        'path',
    ];
}
  • routes/web.php
+    // Asset Routes...
+    Route::get('assets/{asset}/download', 'AssetController@download')->name('assets.download');
+    Route::resource('assets', 'AssetController')->only(['index', 'create', 'store', 'destroy']);
  • app/Http/Controllers/AssetController.php
<?php

namespace App\Http\Controllers;
use App\Asset;
use App\Http\Requests\StoreAsset;
use Illuminate\Support\Facades\Storage;
class AssetController extends Controller
{
    public function index()
    {
        $assets = Asset::query()->paginate();
        return view('asset.index', compact('assets'));
    }

    public function create()
    {
        return view('asset.create');
    }

    public function store(StoreAsset $request)
    {
        $file = $request->file('file');
        $path = $file->store('assets', 's3');
        if (!$path) {
            abort(500);
        }

        $asset = new Asset([
            'model' => Asset:class,
            'name' => $file->getClientOriginalName(),
            'size' => $file->getSize(),
            'type' => $file->getMimeType(),
            'path' => $path
            'disk' => 's3'
        ]);
        if ($asset->save()) {
            return redirect()->route('assets.index')->with('success', __('messages.saved'));
        }

        return redirect()->route('assets.index')->with('error', __('messages.could_not_be_saved'));
    }

    public function destroy(Asset $asset)
    {
        if (Storage::disk($asset->disk)->exists($asset->path) && !Storage::disk($asset->disk)->delete($asset->path)) {
            abort(500);
        }

        if ($asset->delete()) {
            return back()->with('success', __('messages.deleted'));
        }

        return back()->with('error', __('messages.could_not_be_deleted'));
    }

    public function download(Asset $asset)
    {
        return Storage::disk($asset->disk)->download($asset->path);
    }
}
  • app/Http/Requests/StoreAsset.php
<?php

namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreAsset extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'file' => 'required'
        ];
    }
}
  • resources/views/asset/create.blade.php
@extends('layouts.app')
@section('content')
<div class="card">
    <div class="card-header">
      {{ __('Create New') }}
    </div>
    <div class="card-body">
        <form method="post" action="{{ route('assets.store') }}" enctype="multipart/form-data">
        @csrf
        <div class="form-group">
            <label for="name">{{ __('File') }}</label>
            <input type="file" class="form-control" name="file"/>
        </div>
        <button type="submit" class="btn btn-primary" dusk="upload">{{ __('Upload') }}</button>
        </form>
    </div>
</div>
@endsection
  • resources/views/asset/index.blade.php
@extends('layouts.app')
@section('content')
<div class="card">
    <div class="card-header">
        {{ __('Assets') }}
    </div>
    <div class="card-body">
        <table class="table">
        <thead>
            <th>{{ __('ID') }}</th>
            <th>{{ __('Image') }}</th>
            <th>{{ __('File Name') }}</th>
            <th>{{ __('File Size') }}</th>
            <th>{{ __('Created At') }}</th>
            <th>{{ __('Actions') }}</th>
        </thead>
        <tbody>
        @foreach($assets as $asset)
            <tr>
                <td>{{ $asset->id }}</td>
                <td><img src="{{ route('assets.download', $asset->id) }}" width="150"></td>
                <td>{{ $asset->name }}</td>
                <td>{{ number_format($asset->size) }} Bytes</td>
                <td>{{ $asset->created_at }}</td>
                <td>
                    <form action="{{ route('assets.destroy', $asset->id)}}" method="post" class="d-inline">
                    @csrf
                    @method('DELETE')
                    <button class="btn btn-danger" type="submit" dusk="delete">{{ __('Delete') }}</button>
                    </form>
                </td>
            </tr>
        @endforeach
        </tbody>
     </table>
    {{ $assets->->appends(request()->query())->links() }}
    </div>
</div>
@endsection

まとめ

ローカルの開発環境では s3ドライバーを使って MinIO に保存し、AWS で運用時には S3 にそのまま保存する環境を作りました。

参考サイト

WSL と VSCode を使って Vue の開発環境を整えてみる

こんにちは, Web事業部の西村です
今回はタイトルにもある通り WSL(Windows Subsystem for Linux) と VSCode(Visual Studio Code) を用いてVueの環境を整えてみたいと思います

目次

なぜWSLを使うの?

まず, なぜWSLを使うかというお話です
cross-env というnpmパッケージがあります
npmスクリプトを実行する際に, 任意の環境変数に変更できるというものです
しかし, このパッケージはWindowsでは正常に動作しません
そこで, WSL内のLinux環境を使って開発を進め, 快適に開発しようということです

この記事で取り扱わないこと

  • WSLに関する解説
  • Linuxの解説
  • cross-envの解説
  • Vueに関する解説

WSLのインストール

1: 設定を開き アプリ を選択します
2: 画面右側にある 関連設定プログラムと機能 を選択します
3: 新たに出たウィンドウにある Windowsの機能の有効化または無効化 を選択します
4: さらにウィンドウが出るので Linux用Windowsサブシステム にチェックを入れます
5: 再起動が促されるので再起動します

Linuxディストリビューションのインストール

下記のリンクからMicrosoft Storeに移動し好きなディストリビューションをインストールします
WindowsでLinuxを実行する

この記事では Ubuntu をインストールしたものとして解説します

VSCodeのインストール + 拡張機能のインストール

1: 下記のサイトからインストーラーをダウンロードしインストールします

⚠注意
インストール中 PATHへの追加 という項目がありますが, 必ずチェックを入れておいてください

2: インストール完了後起動させ, 左側のタブから Extensions を選択します
3: Remote と検索し Remote Development を追加します
4: VSCodeを閉じます

Linuxの準備

1: 先ほどインストールしたディストリビューションを起動させます (起動させるとターミナルが開き初期化が始まります)
2: ユーザ名 / パスワードの入力が促されるので設定します

Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: <ユーザ名>
Enter new UNIX password: <パスワード (表示されません)>
Retype new UNIX password: <パスワード確認 (表示されません)>
passwd: password updated successfully
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ユーザ名@PC名:~$

3: 下記のコマンドを順番に実行しアップデートを行います

:~$ sudo apt update
:~$ sudo apt upgrade -y

⚠注意
アップデート中に YES/NO を聞かれる部分があると思いますが, YESを選択してください

4: 下記のコマンドを実行し Node.js をインストールします

:~$ curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
:~$ sudo apt install -y nodejs

5: 下記のコマンドを実行し Vue CLI をインストールします

:~$ sudo npm install -g @vue/cli

6: サンプルのプロジェクトを作成するために下記のコマンドを実行します

:~$ vue create sample_project

すると次のような表示が出ますのでそのまま Enter します

Vue CLI v4.0.5
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint)
  Manually select features

しばらくすると初期パッケージのインストールが完了します

7: インストールが完了したらVSCodeで先ほど作成したWSL内のプロジェクトを開きます

:~$ code sample_project/

⚠注意
ここでVSCodeが起動しない場合,パスが設定できていませんので再度インストールしてみてください

ここまでの手順がうまくいった場合, WSL内のプロジェクトがWindowsのVSCodeで見ることができるようになっているはずです
また, 先ほどまで利用していたターミナルは閉じても問題ないです

:~$ exit

追加の拡張機能と動作確認

1: 起動したVSCodeの ExtensionsVue と検索し, Vetur という拡張機能をインストールします
2: Ctrl + Shift + @ を押しターミナルを起動させ下記のコマンドを実行します

:~/sample_project$ npm run serve

するとビルドが始まり, 開発用のサーバが起動します

3: http://localhost:8080/ にアクセスし, 画面が表示されるかどうかを確認します

最後に

いかがでしょうか, Windowsのみを使い続けている人にはきつい内容かもしれませんが, 1度整えてしまうと使いやすい環境なのではないでしょうか?
Windowsだけれども, UbuntuやMacみたいに開発できるといった点ではメリットなのかもしれません
しかし, WSLでは動作が遅いため, 来年に一般公開される予定の WSL2 が待ち遠しい限りです(WSL2では速度面が大幅に解消されています)
ここまで読んでいただきありがとうございました

蛇足?

(A ・ω・)Dockerでもいいんじゃね?  うん(・ω・私)

AWS Chatbot(beta版)を用いたSlack通知

クラウド事業部 インフラエンジニアの吉岡です。

AWS Chatbot(beta版)を用いたSlack通知を試してみましたので、ご紹介したいと思います。

AWS Chatbotとはどういった機能なのか

Slack チャンネルや Amazon Chime チャットルームに対して通知を行う機能です。
サポートしているサービスの通知をSNSトピックに転送し、
SNSトピックからChatbotを経由して各チャットサービスに表示することができます。
現在対応しているサービスは下記の通りです。

AWS Billing and Cost Managemen
AWS CloudFormation
AWS CodeBuild等の開発者用ツール
Amazon CloudWatch Alarms
Amazon CloudWatch Events
AWS Config
AWS Health
AWS Security Hub
Amazon GuardDuty
AWS Systems Manager

今回はAWS System ManagerのRunCommandを実行し、Slackに通知します。設定する通知フローは下記の図の通りです。

Slackへの通知フロー

手順

・SNSトピックの作成
Amazon SNS→トピック→トピックの作成と進み、適当な名前を付けたトピックを作成します。(サブスクリプションはまだ設定しません。)

f:id:seeds-std:20191114181702p:plain

・CloudWatchEventの設定
CloudWatch→ルールの作成、と進みルールを作成します。
今回はchatbot-testという名前で作成しました。

サービス名:EC2 Simple Systems Manager(SSM)
f:id:seeds-std:20191114182349p:plain

イベントタイプ:すべてのイベント
f:id:seeds-std:20191114182353p:plain

ターゲット:SNSトピック(先ほど作成したトピック)
f:id:seeds-std:20191114182357p:plain

・Chatbotのインストール
AWS Chatbotを選択し、
Chatbotの設定を始めていきます。
通知を送る先となるChatツールを選択します。

f:id:seeds-std:20191114182950p:plain

SlackにChatbotをインストールします。

f:id:seeds-std:20191114183017p:plain

今回はpublicのslacktestというチャンネルに通知するように設定します。
IAMロールは自動作成、ロール名はchatbot-slackとしました。
SNS regionはSNSトピックの設定されているリージョン(今回は東京リージョン)
SNS topicsは先ほど作成したchatbot-testを指定します。

f:id:seeds-std:20191114183152p:plain
f:id:seeds-std:20191114183155p:plain
f:id:seeds-std:20191114183157p:plain

設定が完了すると、SNSトピックにサブスクリプションが追加されていることが確認できます。

動作確認

RunCommandを実行し、Slackに通知されることを確認します。
今回はAWS-RunShellScriptでechoコマンドを実行します。
インスタンス指定
SNS通知なし
の条件で下記の内容で実行します。

#!/bin/bash
echo "Hello chatbot"

実行後に下記の様な通知がSlackに届いていることが確認できました。

f:id:seeds-std:20191114183614p:plain

あとがき

今回はChatbotを用いてSlack通知を行うために必要な作業がどういったものか、勉強を兼ねて試してみましたが、非常に簡単に設定ができました。
現在はbeta版ですので、一部の環境のみですが、シーズではこの機能を利用してAWS Health Dashboardの情報をslack通知する設定を行っています。

CloudTrailが有効化されていることが前提ですが、セッションマネージャーを使ったログイン時に通知が届くような設定もできるようです。
正式なリリースが楽しみですね!

デザインにおける余白の重要性

どうもこんにちは!Webデザイナーの衣笠です。

シーズに入社して、はや4ヶ月。
「仕事終わりのビールが美味しい」と思える日が来るなんて、大人になった…なんて思っています。

この4ヶ月間、実際の案件を通し先輩にフィードバックをもらうことで、デザインの考え方やノウハウなど、多くのことを学んできました。

タイポグラフィや配色など、デザインを構成する重要ポイントは様々ですが、今回はそのなかでも特に学びが多かった「余白の重要性」について書いてみたいと思います。

●余白とは?


「余白」というとその字から、「余った空白の部分」という認識をもたれるかも知れません。
しかしデザインにおける余白とは、デザインをする上で最終的に「余ったもの」ではなく、
デザインを行う最初の段階で設計し作り出すもの
といえます。

余白を上手く使うことで

  • ユーザビリティの向上
  • デザインの印象をつくる
    など、様々なメリットがあります。

制作物に適した余白を設計するためには、まずは余白の役割を知ることが大事です。

●余白の役割


・情報をグループ化する

f:id:seeds-std:20191111201906p:plain

余白を使うことで、コンテンツごとにまとまりを作り、情報を整理することができます。
コンテンツの内容を読む前でも、一目で同じ情報ということが、視覚的に分かります。

・文字の可読性を上げる

f:id:seeds-std:20191111201920p:plain

ユーザーにストレスを与えず、文章を読んでもらうために、文字周りの余白は大切です。
各要素間の余白(見出し、本文、テキストが入るボックス)のみならず、
文字間や行間なども、文字の可読性を上げる重要ポイントです。

・視線の誘導を行う

f:id:seeds-std:20191111201932p:plain

要素間の余白を調整することで、ユーザーの視線の動きをコントロールすることも可能です。
上の図においては、ユーザーの視線は左上から右下へと「Z」の字のように流れるように、余白の近接間を調整し、視線の流れを設計しています。

・ユーザーの行動を補助する(手順を示す)

f:id:seeds-std:20191111201946p:plain

重要なボタンの周囲には、余白を十分にとり他の要素を配置しないなど、目立たせたい要素を明確にすることで、ユーザーの行動を補助することも可能です。

余白を使用し、ユーザーが次に取るべき行動を分かりやすく提示することで、ユーザーの迷いをなくす・負荷のかからない設計を行えます。

・デザインの印象をつくる

余白の役割は、ユーザビリティの面だけでなく、デザインのビジュアルにも大きな影響を与えます。
まだ余白の感覚が掴めていない新人デザイナーは、余白を恐れて詰め込みがちなデザインをする傾向があるといいますが、余白を上手く取り入れることで、ゆったりとした高級感のあるデザインを作成することも可能です。

●余白は大事!


余白において一番大切な役割は、「ユーザビリティの向上」です。

  • 情報整理がされておらず、文字も読みづらい
  • 伝えたいことがひと目で明確に分からない

このようなデザインでは、どんなに良いコンテンツが掲載されていても、ユーザーには届きません。

「余白」が重要なのは、デザイン全般的に言えることですが、Webデザインだとその重要性がより顕著に現れると思います。
ユーザーはサイトをくまなくチェックするわけではなく、
「このサイトに自分が求めている情報はあるか?」と、情報を流し読みしています。

ユーザーの求める情報を掲載していたとしても、それが目に留まらず、
「自分の求めている情報が載っているか分からない」と判断されてしまうと、
サイトから離脱(→他のサイトに移る)となってしまいます。

明確に情報を提示し、ユーザーの視線を導くために、余白は大きな役割を果たします

●まとめ


以上、今回は「デザインにおける余白の重要性」というテーマでお送りいたしました。

デザイナーとしてレベルアップしていくためには、余白の使い方をマスターする必要がありそうですね!
より良いデザインができるように、日々精進していきたいと思います!

Page 1 of 17

© SEEDS Co.,Ltd.