寝ても覚めてもこんぴうた

プログラム書いたり、ネットワーク設計したり、サーバ構築したり、車いじったり、ゲームしたり。そんなひとにわたしはなりたい。 投げ銭は kyash_id : chidakiyo マデ

Slackに匿名で投稿する仕組み、Workflowでやれるじゃん、と思ったので作った

f:id:chidakiyo:20210209204555j:plain

Slackに匿名で投稿できると嬉しい人もいるかな?と思ったので以前botみたいなものを使って実現している人を見かけていて、ちょっと手軽に運用するにはめんどいなーと思ったので、workflowで作れんじゃない?と思いついたので作ってみました。

Workflowはどんな感じ?

Workflowの使い方から説明するのは他の記事にまかせて、どのような構成にするかを手っ取り早く書きます。

f:id:chidakiyo:20210209204719p:plain

こんな感じ。
簡単に解説すると

最上段が、workflowを有効化するチャンネルへの設定。
2段目が workflow を実行するとフォームが開いて、テキストエリアに入力を促される。

f:id:chidakiyo:20210209204741p:plain

3段目がworkflowを実行したチャンネルに対して、設定したフォーマットで入力された値を出力しますという感じ

f:id:chidakiyo:20210209204755p:plain

実行するとどんな出力が?

workflowを実行すると以下のようなフォームが表示されます

f:id:chidakiyo:20210209204810p:plain

フォームに入力し実行すると以下のような文字がSlackのチャンネルに出力されます

f:id:chidakiyo:20210209204822p:plain

匿名にするとカオスにならない?

上の例は、利用者を信じて実行者のログなど取れませんが、
workflowで入力値とそのユーザを特定の場所に出力する、という設定も可能なので、
ログを取ろうと思えば取れます。

終わりに

workflow、コード書かなくてよいし便利だなぁ。

ではでは。

GAEのカスタムドメインのTLS1.0/1.1を無効化する

f:id:chidakiyo:20210208112941j:plain

GAEでカスタムドメインを利用しており、TLS1.0/1.1 を無効化したいという人もいるかと思います。
今回はその流れをサラッと書いていこうと思います。

なぜ TLS1.0/1.1を無効化するのか

私の説明より こちら の素晴らしい記事を読むのが良さそうです。(手抜き)

GAEで無効化する流れ

GAEのカスタムドメイン(GAEの標準のドメインも)のTLSを無効化するためにはユーザサポートに連絡する必要があります。
ユーザ側からできることはありません。

自分のサイトがTLS1.0/1.1が有効化されているかのチェック

こちら のサイトを利用するのが便利です。

ドメインを入力し、チェックにはしばらく時間が必要です。
数分待つと、チェックもとのサーバのいずれかを選択すると、詳細のページに飛べます。

Cipher Suites の一覧に TLS1.0/1.1 の項目があると有効な状態となります。

f:id:chidakiyo:20210208113058p:plain

サポートとどのようなやり取りをする必要があるか、また適用の期間

  • GAE で利用している(全サービス)のドメイン一覧(appspot.com)以外のものを全て伝える
  • 適用するcipherを選択する

cipherは以下から選択できます

1. default setting (cipher_settings is not set)
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA

2. ciphers_without_3des
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA

3.  ciphers_without_3des_and_rsa
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

4. ciphers_without_3des_and_aes128
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA

5.  ssl_good_ciphers
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

上記の情報をサポートにお伝えし、適用を待ちます。

具体的な適用までの期間は書きませんが、「思ったより時間がかかる」と思っていたほうが良いです。
TLS1.0/1.1の無効化を考えている方は早めに依頼することが必要です。(もし適用完了したい日程が決まっているなら)

ではでは。

参考

Terraformやコマンドで作成したCloud LoggingのLog RouterがPub/Subに送られない

f:id:chidakiyo:20210208104052j:plain

ちょっと前にTerraformでLog Routerを作成し、Pub/Subにログを送ろうとするとうまく送れず、
Web UIで作成するとうまく送れるということがありました。

雰囲気問題点がわかった気がするのでメモしておきます。(2021/02/08現在の情報です)

問題点

Web UIからLog Routerを作成した場合には、シンク作成時に割り当てられるSAに Pub/Subscribe パブリッシャーのロールが付与されるが、Terraform/gcloudコマンドで作成した場合にはその権限が付与されない。

Web UIから作成した場合にはシンク作成時にPub/Subトピックを新規作成することができ、その際に作成されたSAでPub/Subにパブリッシャーロールが付与されます。
既存のトピックを指定するとそれが付与されません。

また、 Terraform/gcloudコマンドの場合にはそもそもトピックを同時に新規作成するオプションが存在しないため、SAに権限が付与されません。

どうすれば良い?

シンク作成時に割り当てられるSAに対してPub/Subパブリッシャーのロールを付与する。

参考

https://cloud.google.com/logging/docs/export/configure_export_v2#dest-auth

GAE/go のデプロイが遅くなったと思ったときに読む記事

f:id:chidakiyo:20210208095710j:plain

タイトルの通り、GAEのデプロイにCloud Buildが裏側で利用されるようになり、
なにやらキャッシュとかうまいことやってくれようとしています。

しかし、そのキャッシュの作成なのか、展開なのか、若干その扱いが内部的にうまく行ってないようで、
デプロイを何度もし続けているとどんどん遅くなりタイムアウトすることも多くなるようです。

それを解決できそうな方法をメモしておきます

どんな状況になるか

デプロイのタイムアウト(10分)が頻発する

デプロイの途中のプロセスでしばらく固まる
(exporterのステップで非常に時間が大きくかかる)

解決できそうな方法

gcloud app deploy する際に --no-cache オプションを付与する

たったこれだけ。

これでCloud Buildのキャッシュを使わずにデプロイされるようになり、
比較的安定した速度で デプロイ出るようになりそうです。

速くなったか

しっかり計測はしていませんが、
手元のプロジェクトでも、遅めになってきたGAEのプロジェクトに関しては少し速くなっているように見えます。(データはありません)

参考

Chrome の HSTS 状態を確認する

f:id:chidakiyo:20210205111332j:plain

HSTS ってなに?

HTTP の Strict-Transport-Security。HSTSと略されます。

ウェブサイトがブラウザに対してHTTPSの代わりにHTTPSを用いて通信をする用に指示するためのもの。
HTTPからHTTPSにリダイレクトする際に中間者攻撃の機会を作ってしまうリスクがあるため、
ブラウザ側に、「http:// と打ち込まれても https:// でアクセスしてくださいね」とおぼえさせるための機能です。

Chrome, Firefox, Safari の場合にはブラウザ側ですでにHSTSドメインを認識している(登録されている)プリロードHSTSというものもあります。
(.app, .dev ドメインなどは最初からプリロードHSTSドメインです。httpアクセスができません。)

そのHSTSという機能はブラウザ側が覚えるものなので、時折状態をチェックしたいということがあると思いますので、その方法を下記します。

Chrome 上で HSTS が有効になっているかチェックする

Chrome で HSTS 状態を確認する場合には以下のURLを入力します

chrome://net-internals/#hsts

特定のドメインの HSTS 状態を確認する

上から2段目あたりの Query HSTS/PKP domain の項目の、
Domain: と書かれた入力エリアに調べたいドメインを入力し、 Query ボタンを押して調べます。

HSTS がChrome上で有効になっていないドメインだと Not found と表示されます。
HSTS がChrome上で有効になっているサイトだと各種項目が表示されます。

f:id:chidakiyo:20210205111202p:plain

HSTS を無効化したい場合

検証のために、一時的にHSTSを無効化したい場合などがあると思います。
その場合には一番下の Delete domain security policitsドメインを入力し、実行します。
(ちなみに、当たり前ではありますがプリロードHSTSドメインは削除できません)

ドメインに対するHSTS設定を削除しても、そのドメインのサイトにアクセスし、再度HSTSヘッダを受信すると、
ブラウザにHSTSドメインとして認識(登録)されてしまいますので、ご注意を。

ではでは。

参考

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Strict-Transport-Security

Go で Spanner とよろしくやるためにガチャガチャやっている話

f:id:chidakiyo:20201214201606j:plain

この記事は Go Advent Calendar 2020 14日目 の記事です。

みなさん Go してますか?
Spanner も触ってますか?

最近やっと部分的に本番環境で Spanner を利用し始めました。

Spanner のスキーマなどを git で管理しつつ、チーム内でレビューなどをしつつ運用する方法として、 以下のツールたちを利用しています。

試したツールたち

最終的に利用しているツールは

  • wrench
  • yo

  • お好みで : hammer (としたいところだが使えてない、下記)

となっていますが、以下のイメージで利用しています。

全体の関係

以下の図のような関係になっています。

f:id:chidakiyo:20201214201516p:plain

1. DB の初期スキーマを適用する

wrench を利用します。
事前に schema.sql など、スキーマファイルを作成しておきます。

最終的には yo がスキーマの定義をみて Mutation を生成するコードを生成するので、 検索の条件にする必要があるカラムなどは適切にインデックスを付与するなどします。
SQLでは自由にかけてしまいますが、単純な利用方法であれば、インデックスを貼らないカラムに対する条件で検索ができるようなコードはかけなくなるので安全とも言えるかもしれません。

コマンドは

wrench create --directory {DDLファイルがおいてあるディレクトリ}

という感じで実行します。

2. 開発中にカラムに変更がある場合にはマイグレーションを行う

wrench で以下のコマンドを実行すると、マイグレーション用のファイルが生成されます

wrench migrate create --directory ./

コマンドを実行するとファイルが生成されますが、連番のブランクファイルになっています。
そのファイルに alter 文を記述し、カラムの変更を適用するイメージになります。

ここの alter 文を hammer を利用しようとしましたがちょっとうまくいきませんでした。(図の2')

3. miigration ファイルを DB に適用する

これも wrench を利用します。
以下のコマンドで適用します。

wrench migrate up --directory {DDLファイルが置いてあるディレクトリ}

4. 開発のためのコードを DB のスキーマから生成する

yo というツールを利用します。
以下のコマンドを実行します

yo $(SPANNER_PROJECT_ID) $(SPANNER_INSTANCE_ID) $(SPANNER_DATABASE_ID) -o {生成したコードを格納したいディレクトリ}

wrench は project_id, instance_id, database_id は環境変数で渡していましたが、 yo は直接コマンドラインで渡します。

生成されるファイルは

  • yo_db.yo.go
  • {table_name}.yo.go

が最低限生成されます。
生成されたファイルは .yo.go になるので、自動生成されたコードをファイル名から容易に判別できます。

おまけ1

Go のアドベントカレンダーなので、Go コードを出さねば・・・と思ったので...
Spanner の Go クライアントは内部的にセッションプールの仕組みを持っています。
以下のような雰囲気で設定を行います。

const healthCheckIntervalMins = 50
const numChannels = 4
var config = spanner.ClientConfig{
    SessionPoolConfig: spanner.SessionPoolConfig{
        MinOpened:           100,
        MaxOpened:           numChannels * 100,
        MaxBurst:            10,
        WriteSessions:       0.2,
        HealthCheckWorkers:  10,
        HealthCheckInterval: healthCheckIntervalMins * time.Minute,
    },
}

一度、Spanner を利用したアプリケーションを検証環境にデプロイしてテストしていた際に、 ある程度リクエストを受けるとなぜか Spanner がブロックし、アプリケーションが全く応答しなくなるという問題にぶち当たりました。

数百のリクエストを投げると、ある時からリクエストが全部タイムアウトして、全くサーバが動いている様子がない、 というなかなか恐ろしいものでした。

原因としては、 ReadOnlyTransaction() で取得したトランザクション(connection?)は、 defer で Close() しないとプールの中の Connection が枯渇して ReadOnlyTransaction() がブロックし続けるというものでした。

おまけ2

おまけ1で得た知見。

zagane (https://github.com/gcpug/zagane) を使いましょう!

zagane は以下を防いでくれます

unstopiter: it finds iterators which did not stop.
unclosetx: it finds transactions which does not close
wraperr: it finds (*spanner.Client).ReadWriteTransaction calls which returns wrapped errors

自分の使い方が悪いのか、モノレポ構造で使っているのが悪いのか、
極稀に検知してくれないケースが自分の環境では有るのですが、これは Spanner を利用するなら必須と言っても良いものです。

まとめ

と、ここまで書きましたが、実際には既存の Datastore から単純に一部移行したぐらいでしか利用できていません・・><
数百リクエスト/秒 ぐらいで利用しているので、CPU 負荷も 5% も行かないぐらいでめちゃくちゃ安定して稼働してます。Spannerすごい。

なんかもっと書きたいことがあったような気がするけど書いているうちに忘れてしまった・・・ま、いっか

明日の記事は hajimehoshi さんの 「Go におけるアラビア語描画について」 です。楽しみですね。

ではでは。

GCP の DNS を yaml ファイルを利用して管理する

f:id:chidakiyo:20201210184827j:plain

GCPDNS を利用する場合、Web UI や コマンドでレコードをポチポチ投入するの大変ですよね。

今回は Cloud DNS のレコードをまるごと yaml で管理し、 export/import する方法を書いてみます。

必要なもの

試す際に Google Cloud SDK(gcloud) のインストールは必須です。

必要ではないですが、以下の手順はすでに Cloud DNS に zone が作成され、ある程度のレコードが有る想定で書いています。

DNS に登録した内容を yaml ファイルに一括出力する

コマンドは以下のような感じになります

gcloud dns record-sets export dns-record.yaml --zone=ZONE -z {ZONE_NAME}

上記の dns-record.yaml は出力先ファイル名です。
出力したいディレクトリやファイル名を適当に渡すことで実行ディレクトリ以外の場所にもファイルを出力できます。

今回はフォーマットを特に指定していませんが、 Bind のゾーンファイル形式などでの出力も可能なようです。(未確認)

出力した yaml ファイルは後述する Import 機能で利用でき、また、git などで差分管理が行えるので、チームで変更内容のレビューをして適用する、などのフローに利用することもできるかもしれません。

出力した yaml ファイルを Import し、DNSに反映させる

出力したファイルを以下のようなコマンドで適用できます。

gcloud dns record-sets import dns-record.yaml --zone=ZONE -z {ZONE_NAME} --delete-all-existing

ポイントは --delete-all-existing フラグなんですが、これは投入前にすでに存在するレコードをすべて消すというオプションだと思われます。このフラグを付与しない場合、すでに存在する各種レコードに対して重複したレコードはエラーになるため、yaml まるごとの適用という運用ができなくなります。
このあたり深く振る舞いを調べていないため、各自運用の際に検証してみてもらえると良いと思います。(コメントもください)

おわりに

普通は Terraform などを利用して DNS のレコード管理などを行うのが主流かと思いますが、
GCP の標準機能でもある程度それっぽいことができますよ。
という感じのお話でした。

ではでは。