env-injector作るときに考えてたこと

medium.com

env-injectorが「問題がある」って言われてもうた。ツライ……

というわけで言い訳エントリです。見苦しいですね。


env-injectorの作成時、空の環境変数を作らずに「DescribeParameterでパラメータ一覧ぶっこ抜いてprefixにマッチするものをinjectする」っていうのも考えたんですけど、以下のような理由からやめました。

1. DescribeParameterはIAMのポリシーで必要となる一部のパラメータだけに制限することができない。

開発環境から本番環境のパラメータ一覧が見えたり、別アプリケーションのパラメータ一覧が見えたからって「だから何?」ってハナシもありますが、 なんとなく嬉しくないかなぁ……と。

2. 意図しない環境変数をinjectしないか?

ssm側のパラメータ一覧を全部読み込むことになるので、ちょっとした確認での実行時に意図しない環境変数まで読み込んでしまうコトを懸念しました。

自分で空の環境変数用意するんなら、必要なものだけinjectするだろうし、意図せずinjectするコトはないだろうと思ってみたり。

3. dockerのentrypoint用を最初から想定

パラメータの一覧の「正」とするモノはアプリケーション側にあった方がいい(パラメータストアを見ないと一覧がワカラナイとかツライ)し、 空の環境変数用意するのは、DockerfileのENVで指定すればそんなに手間じゃない、と考えました。

また環境変数のキーが隠蔽できない件も、DockerfileのENVで記述するような時点で隠蔽するものではないだろうと。


最終的には「id:kakku22兄さんからの宿題で、数ヶ月放置したあげくの回答用のPoCだから何でもいっか」っていう雑な決断ですけどね。。。

ざっくり見たカンジ、スクリプトに組み込むんならexecするenv-injectorより、ssm2envの方が便利だと思います。

そんなこんなでパラメータストア周りのツールでイロイロ選択肢が増えればいいんじゃないかなぁ、と個人的には思います。


(追記: 2017-08-04)

なんか元記事の中の方に気を使わせてしまったみたいでスミマセン。

もともとがやっつけで作ったもなので対応できないユースケースがあるのは当然なので、「イケてない」と思われても仕方ないんですけどね。(;・∀・)

んで、実はこっそりDescribeParametersでパラメータぶっこ抜いて環境変数を設定するモードも用意してみました。

# 以下の値がパラメータストアに保存されてるという前提で
#   - prod.wap.DB_USER=admin
#   - prod.wap.DB_PASSWORD=password
#   - prod.wap.DB_PARAM=param
# こんな環境変数を設定しておく
$ export ENV_INJECTOR_PREFIX=prod.wap
$ export DB_USER=user
$ export DB_PASSWORD=

# mode=empty_only: 空の環境変数(DB_PASSWORD)だけ上書き。デフォルト
$ ENV_INJECTOR_MODE=empty_only env-injector printenv | grep DB_
DB_USER=user
DB_PASSWORD=password

# 当然無指定でも同じ挙動
$ env-injector printenv | grep DB_
DB_USER=user
DB_PASSWORD=password

# mode=aggressive: パラメータストアの変数を全部設定するけど、もともと設定されている環境変数(DB_USER)はそのまま
$ ENV_INJECTOR_MODE=aggressive env-injector printenv | grep DB_
DB_USER=user
DB_PASSWORD=password
DB_PARAM=param

# mode=all: パラメータストアの変数を全部設定する。もともと設定されている環境変数があっても上書き
$ ENV_INJECTOR_MODE=all env-injector printenv | grep DB_
DB_USER=admin
DB_PASSWORD=password
DB_PARAM=param

aggressiveallはGetParametersに加えてDescribeParametersのパーミッションも必要になります。
逆にデフォルトのままだと特に追加のパーミッションもいらない、ということで。

……こ、これで、どや?

AWS上で動かすアプリケーションとクレデンシャル情報

AWSで動かすアプリケーションのクレデンシャル情報ってどう管理してますか?
chefやansibleでプロビジョニングしたりするにしても、平文でgit管理するのもアレだし、暗号化してコミットするのも結局扱いにくいし……と悩ましいですよね?

そんな中、こちらのクラスメソッドさんのエントリを拝見したところ dev.classmethod.jp

AWS上で動かすアプリのクレデンシャル情報をパラメータストアから環境変数にぶっこんでくれるツールがあればイケてるんじゃね?」と思いついてしまったので、勢いでPoC的に作ってみました。

github.com

使い方は、空の環境変数用意しておいてから

$ export DB_USER=
$ export DB_PASSWORD=

プレフィックスを指定して、env-injector経由で任意のコマンドを実行します。

$ ENV_INJECTOR_PREFIX=prod.wap env-injector printenv | grep DB_
DB_USER=scott
DB_PASSWORD=tiger

するとパラメータストア(この例ではprod.wap.DB_USERとprod.wap.DB_PASSWORD)の値が環境変数に入った状態でそのコマンドが実行されます。

dockerの場合ですと、以下のDockerfileのようにENTRYPOINTで指定するといいんじゃないかなぁ……と。

FROM golang AS build-env
RUN CGO_ENABLED=0 go get github.com/okzk/env-injector

FROM alpine
RUN apk add --no-cache ca-certificates
COPY --from=build-env /go/bin/env-injector /usr/local/bin/
ENTRYPOINT ["env-injector"]
ENV DB_USER= DB_PASSWORD=

CMD ["printenv"]

プレフィックスを指定しなければなんの影響もありませんし、

# docker build -t test .
# docker run --rm test | grep DB_
DB_USER=
DB_PASSWORD=

環境を切り替えるのもラクチン。

# docker run --rm -e ENV_INJECTOR_PREFIX=prod.wap test | grep DB_
DB_USER=scott
DB_PASSWORD=tiger

# docker run --rm -e ENV_INJECTOR_PREFIX=stg.wap test | grep DB_
DB_USER=admin
DB_PASSWORD=password

アプリケーション本体は普通に環境変数で設定を受け取るように作るだけでOKですので、アプリケーションとパラメータストアが密結合になることもありません。


ECSで動かすアプリケーションも適切にtask roleと組み合わせればクレデンシャル管理もバッチリになる、ということで。

nohupなncでのtarなファイル転送

TB級のデータ転送のように、scpがかったるくてやってられない場合にncでファイル転送をしようというケースありますよね?
そんなケースでは当然相当時間がかかるんで、途中で死なないようにnohupをつけたい、と思うわけで。

んで、そのままnohupつけると動かなくなるんですが、よくワークアラウンドを忘れるのでメモを残しておきます。

# ホストやポート番号等は適当に読み替えてください

ファイル受信側

nohup nc -d -l 12345 2> nohup.out | tar xvf - &

ポイントは2点

  • nohupが標準入力をcloseするので、-dでncが標準入力を無視するように指定
  • nohupは特に指定してないと標準エラー出力を標準入力とマージするので、標準エラー出力の出力先を明示的に指定

ファイル送信側

nohup tar cf - files | nc 192.168.10.10 12345 &

こっちのポイントは

  • ファイル名のような余計な出力をしないよう、tarのzオプションなんかはつけない

以上ですー

MackerelとECSのダイナミックポートマッピング

当方、現在の担当業務的にMackerelを両手で数えられるくらいのサーバにしか導入しておらず、しかも初期に設定をしたあとは絶賛放置中という超ライトユーザなのですが、先日なんの因果か他部署の方から「ECRのダイナミックポートマッピングしているときのコンテナのメトリクス取るのどうすればええん?」という相談をうけてしまいました。

完全無欠のMackerel情弱としては、極々テキトーなやり取りをせざるを得なかったのですが、なんだかそれなりにイイ感じまとまったみたいです。

kakakakakku.hatenablog.com kakakakakku.hatenablog.com

結論、id:kakku22 さんカッケー。

まあそれだけだとアレなわけで、事情があって歯牙にもかけてもらえなかった別の方法をこのエントリでは書いてみようと思います。


ざっくり提案したのは以下のようなやり方。なお当方テキトーなので自分で試してないです(ぉ

ECSのtask-definitionで以下のように複数コンテナが動くようなタスク設定をする

  1. メトリクスを取りたい対象のコンテナ
    → 適当なポートでサービスが動いていて、そのポートでメトリクスをとれる
    → hostとのポートマッピングは動的で、host側からアクセスではポート固定できない
  2. mackerel-agentを動かすコンテナ
    → dockerのlink機能で上記のコンテナのポート(こっちは固定指定可)にアクセスしてメトリクス収集

要するに1タスクを1ホストとみなして、そこの中でメトリクス収集を完結させちまおう、というやり方ですね。
そーすることでMackerelの管理画面でもroleでのグラフもいい感じにまとまって見れるんじゃね?的な?的な?

 

やろうと思えば設定もカンタンで管理画面上も管理しやすい、という案なのですが、既に書いたように採用は見送られました。

理由は単純で、Mackerelの課金がホスト単位なので、1タスク1ホストとかでポンポン設定入れちゃうとアホみたいにオカネがかかるから、という。。。

そんなわけでMackerel様としては「ホストあたりの基本料金を極々安くして、その代わりメトリクス数で従量課金する」みたいな設定も可能にしていただけるとイイなぁと思う次第であります。
# じゃねーとみんなdatadogに逃げちゃうよ?

Symantecの証明書問題私的まとめ

Symantecの証明書でアレコレざわついているので、自分用にまとめます。

経緯等

以下にまとまっていまるので省略。

notchained.hatenablog.com

何がおこるか?

https://github.com/sleevi/explainer/blob/master/README.md

ざっくりまとめると以下の2点

  • 該当の証明書の有効期限を短いモノとして取り扱う(最終的には最大279日とみなす)
  • 該当の証明書はDomain Validatedとして扱う(EV証明書がEV証明書として扱われなくなる)

「該当の証明書」って?

https://chromium.googlesource.com/chromium/src/+/master/net/data/ssl/symantec/README.md

  • 証明書チェーンのルートCAの証明書が ここになければセーフ
  • subCAで発行した証明書の場合、それが"Excluded Sub-CAs"に記載されていればセーフ
  • それ以外はアウト

もっと具体的には?

個人的観測範囲で使われていて、該当するCAは以下

3/27くらいからChromeでEV証明書がEV証明書として扱われなくなったんだけど?

WindowsChrome 57では現象を確認できたが、MacChrome 57では確認できず。

経緯は以下

斜め読みしたカンジでは、"Symantecに激おこ事案"とは無関係の単なるバグか?
# タイミング悪すぎやろ。。。

どうすればいいの?

今後どう転ぶかわからないし、巻き込まれたくないならSymantecVeriSignのEV証明書をつかってるトコは、他社に乗り換えればいいと思う。

EV証明書じゃないなら、有効期限が短くなるだけといえば、それだけなので運用回避もアリかと。

私見

Symantecはギルティでも、Symantec発行の証明書を使ってるトコまで巻き込まれるのはツライ。

ただひたすらツライ。

5/2追記

まだちゃんと読んでないけど、リンクだけ

security.srad.jp

docker swarmのオーバーレイネットワークの安定性について

半年くらい前にこんな記事を書いたのですが、まあうまく行きませんでした。

okzk.hatenablog.com

頂いたブコメも試してみたんですけど、結果は芳しくなく。。。

Re: Dockerに載せたサービスをホットデプロイする - okzkメモ

--stop-grace-periodの設定とDockerfileのHEARTBEATとSTOPSIGNALの設定をすれば出来るはず

2016/08/17 06:19
b.hatena.ne.jp

そんな中、元記事のヒトも試してみたようですけど、同じ結果に。。。

h3poteto.hatenablog.com


そんな中、CVE-2016-9962も出ちゃったし、docker 1.13もリリースされたコトだし、ということでdocker 1.13でswarmモードをもう一回試してみました。

インストール後、swarm初期化

# docker swarm init
# docker service create --update-delay 5s -p 80:80 --name test --replicas 2 nginx

別ウインドウでログ等を確認しつつ

# watch -n 0.3 'curl -sI  http://localhost; docker ps -q | xargs -i sh -c "echo ----------- {};docker logs --tail 5 {}"'

パタパタイメージが切り替わるようにやる気なくワンライナー

# set -e
# while : ; do docker service update --image nginx:stable test ; sleep 15 ; docker service update --image nginx test; sleep 15 ; done

数十分放置してみましたが、特に問題ありませんでした。


というわけで元記事に対する半年遅れの回答になりますけどdocker 1.13のswarmモード使えば良いんじゃないでしょうか?

ubuntu 16.04でcloud-initでapt-get upgradeできない件

最近ubuntu 16.04を使い始めたんですけど、簡易プロビジョニングということで、 cloud-initのuser_dataのスクリプトで以下のようにパッケージの更新をしかけていました。

apt-get update
apt-get upgrade -y
# 他、アレコレと……

ところが先週くらいから、コイツが完全にハングするようになってしまいました。(´・ω・`)

原因はsnapdが更新されて、コイツがアップデートの中でsnapd.boot-ok.serviceを起動しようとするんですが、 cloud-initのuser_dataで与えられたスクリプトはシステムが完全に起動する前に実行されちゃうんですね。

ということで、

  • snapd.boot-ok.serviceがmulti-user.targetの起動を待つため、apt-get upgradeが完了しない
  • apt-get upgradeが完了しないから、multi-user.targetがいつまでたっても起動しない

という完全にデッドロックです。\(^o^)/

ソッコーでバグレポートも上がったんですけど、9/16日現在、まだcloud-initでのapt-get upgradeはハングします。 https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1621336

しょうがないので、一旦snapdを更新対象から外してapt-get upgradeするように運用回避してます。

apt-get update
echo snapd hold | dpkg --set-selections
apt-get upgrade -y
echo snapd install | dpkg --set-selections

んー、メンドクセ。