Shogo's Blog

Feb 28, 2019 - 1 minute read -

新元号の候補約4510万件が漏洩!!

平成の次の元号候補、4510万4656件の漏洩が確認された。 テキスト形式 (301MB) gz圧縮版 (108MB) 政府は「新元号、情報管理を徹底へ 漏洩なら差し替え」との方針を示しており、 早急な差し替え対応を行うと思われる。 2019-04-01 追記: $ curl -s https://t.co/OCaFAriJIt | cat -n | grep 令和 726041令和 無事漏洩してました!!! — Ichinose Shogo (@shogo82148) 2019年4月1日 追記ここまで と、まあ、二番煎じなわけですが。 新元号は漏洩すると変更されるということなので常用漢字2文字の全組み合わせ約228万通りをすべて記載したテキストファイルを作成しました。漏洩させていきましょう。https://t.co/G06utDbgka pic.twitter.com/8UcPDqNdXo — いんぐらむ (@kazuokiriyama) 2019年2月26日 ただ、このツイートのリプライのもあるとおり漏洩漏れがあるようですし、 新元号に使われる可能性のある漢字は常用漢字ではない可能性だってあると僕は考えいます。 だって、お国のやることですからね。下手したら改元に合わせて「常用漢字の見直しもやる」ということだって考えられます。 というわけで、僕は ShiftJIS, EUC-JP で表現可能な文字列まで範囲を広げることにしました。 Unicodeへの統一が進んでいるとはいえ、 ShiftJIS, ECU-JP で動いているレガシーなシステムもあるでしょうし、この範囲に収めるだろうなという予想です。 ShiftJISからUnicodeへの変換には規則性がないので、変換テーブルを使う必要があります。 Goのコードを漁った ら以下の変換表を参照していたので、これを利用しました。 https://encoding.spec.whatwg.org/index-jis0208.txt 非漢字も含まれているので、雑に漢字を絞ったあと、 curl https://encoding.spec.whatwg.org/index-jis0208.txt | grep CJK | cut -f3 | cut -d' ' -f1 | sort | uniq > kanji.txt 直積列挙スクリプトに突っ込めば出来上がり。

Feb 12, 2019 - 2 minute read - go golang aws lambda

外部サービスでもIAM Roleで認証がしたい!

背景 外部サービスのAPIやWebHookを叩くときには、多くの場合 API トークンが必要になります。 もちろん API トークン無しでも叩けるサービスはありますが、GitHub APIのようにトークン無しではリクエスト数が大きく制限されたり、 一部機能が制限されてしまう場合があります。 外部連携サービスが増えてくると、このAPIトークンをどうやって管理するかが問題になってきます。 プロダクションに投入されているサービスは普通複数のサーバーから構成されており、各サーバーにAPIトークンを配布するのはちょっと面倒です。 この問題に対して、以下のようなことが行われて来ました。 プライベートネットワークからのアクセスに限定した Proxy を立てる APIトークンの管理は Proxy に任せる DevOpsが注目され、Slackの利用が広まったころに、このような目的で書かれたProxyサーバーがよく登場しました。 社内IRCをSlackに移行した時にやったこと この記事で紹介されている kayac/nopaste Slackboard〜Slackプロキシサーバ in Go〜 Slackプロキシサーバ〜slackboard〜を利用したメルカリのSlack活用法 App::Ikachan - 様々なサーバのバッチ処理の結果等を IRC のチャンネルに通知するサーバ (IRCはHTTPで動いているわけではないし、大本の目的もコネクション維持だけど、認証も代理でやってくれる) しかし、これらのサーバーはSlack専用だったりIRC専用だったりします。 Slackだけじゃなくって、GitHubにコメント登録したり、Mackerelのグラフアノテーションを投稿したり、 他のサービスとも連携したい! 最近はどんなAPIもHTTPで提供されるようになったので(IRCは・・・ウッ・・・そんなのなかった)、もっと汎用的に書けるのではとやってみました。 実装 APIトークンの保管場所として AWS Systems Manager Parameter Store を採用しました。 Parameter Store からAPIトークンを取り出す部分と、実際にAPIを叩く部分は AWS Lambda を使用します。 各サーバーに Forward Proxy デーモンを立てておき、APIを使いたいアプリケーションはこのProxyを経由するようにします。 この図ではEC2インスタンスを例にしていますが、IAM Roleを付与できるAWSのサービスであれば何でも (ECS, Lambda, CodeBuild, etc.) APIにアクセスすることができます。 外部サービスのAPIを叩くのが Lambda 関数というのもポイントです。 APIトークンをヘッダーに設定するのか、URLの一部に含めるのか、クエリストリングに含めるのか・・・といった設定方法はサービスによってまちまちです。 Lambda 関数がこの辺の設定を肩代わりしてくれるので、APIトークンの扱いを気にする必要はありません。 また、API利用時にうっかりAPIトークンを漏らしてしまう心配もなくなります。 APIトークンの管理をしたいんじゃない!!ただ、APIを叩きたいだけなんだ!!!! という思いから、Proxy デーモンはシークレットに関しては何も関与しません。

Feb 7, 2019 - 3 minute read - acme python aws lambda

Let's Encrypt の証明書取得を AWS Lambda でやってみた

背景 ここ数年で暗号化されていないHTTPは減り、常時TLSが当たり前になってきました。 公開用のページはもちろん、開発段階のページでもTLSは必須です。 普段はAWS上で開発をしているので、AWS Certificate Managerを利用することが多いのですが、 ちょっとしたお遊びにELBやCloudFormationを使うのはオーバーキルです。 そこで EC2 にもインストールできて、無料で使える Let’s Encrypt を使って証明書を発行することを考えました。 Let’s Encrypt で発行できる証明書は期間が90日と短く、60日ごとの自動更新が推奨されています。 証明局とAPIとAPIクライアントの実装例は提供するから、あとの自動化部分は自前で頑張ってねという感じなので、自動化部分を頑張らないといけません。 今回は実行環境として AWS Labda、ACME(Automatic Certificate Management Environment)クライアントとして certbot、 認証方法に dns-01、認証に必要なDNSレコードの書き換えに AWS Route 53 を使用する、という構成にしました。 ソースコードをGitHubに挙げたのと、前回と同様に AWS Serverless Application Repository へ上げたので、ぜひご利用ください。 shogo82148/acme-cert-updater shogo82148/acme-cert-updater on AWS Serverless Application Repository 関連手法 Amazon Linux 2 に certbot をインストールして使う Amazon Linux 2 のドキュメントに TLS 対応のウェブサーバーを立てる例が載っています。 Let’s Encrypt で証明書を取る方法も紹介されているので、まずはこれを利用することを考えました。 付録: Amazon Linux 2 での Let’s Encrypt と Certbot の使用 - チュートリアル: Amazon Linux 2 で SSL/TLS を使用できるように Apache ウェブサーバーを設定する この方法は以下の理由から見送りました。

Jan 31, 2019 - 3 minute read - go golang aws mackerel

サーバーレスでCloudWatchメトリクスをMackerelに転送する

背景 サーバーの監視にMackerelを使っているのですが、 用意されているメトリクスでは足りずカスタムメトリクスを追加することが多々あります。 Mackerel Agent Pluginsを利用すればメトリクスを増やすこと自体は簡単なのですが、 Agentを設置するインスタンスが増えるので、サーバー保守の手間が増えてしまいます。 僕のユースケースでは監視対象はたいていAWSのマネージド・サービスなので、 AWS CloudWatch に投稿されたメトリクスが Mackerel で見れれば十分なことが多いです。 そこで、以下の記事を参考に AWS Lambda と CloudWatch Events を組み合わせて、Mackerelへメトリクスを転送するスクリプトを書いてみました。 Amazon LambdaでCloudWatchのメトリクスをMackerelに監視させる デプロイしてみる 今回はなんと!皆さんの AWSマネジメントコンソールから、クリックひとつでデプロイできるようにしてみました! mackerel-cloudwatch-forwarder ・・・と、その前に下準備が必要です。 MackerelのダッシュボードからAPIキーをコピーしてきて、 AWS Systems Manager パラメータストアに Secure String として登録しておきます。 スクショでは Mackerel のものだと分かりやすいよう /development/api.mackerelio.com/headers/X-Api-Key という名前をつけました。 この名前を後で使うので覚えておきましょう。 次に AWS Lambda の画面を開き、「関数の作成」をクリックします。 「一から作る」「設計図」「AWS Serverless Application Repository」の3つの選択肢が表れるので、 「AWS Serverless Application Repository」 を選択します。 検索BOXに「Mackerel」と入れると、mackerel-cloudwatch-forwarderが 出てくるので、それを選択します。 なお、この選択肢はデフォルトでは表示ないので、「Show apps that create custom IAM roles or resource policies」にチェックを入れましょう。 アプリケーションの内容とパラメーターの設定画面に移ります。 「ParameterName」にパラメーターストアに登録したパラメーター名を入れましょう。 スクショの例では「/development/api.mackerelio.com/headers/X-Api-Key」を入力します。 「カスタムIAMロールを作成することに同意」のチェックボックスを選択したあと、デプロイ!

Jan 30, 2019 - 3 minute read - go golang mysql aws

CloudFormationでECSタスクのドレインをやる

やってみたはいいものの、1年後には仕組みを忘れていそうなのでメモ。 背景 昔はサービス毎にポコポコEC2インスタンスを立てていたのですが、 幸か不幸かインスタンスのリソースが余り気味でした。 そこで、最近流行りのコンテナ技術に乗っかって Amazon ECS (Amazon Elastic Container Service) を使って、 ひとつのインスタンスに複数のサービスを載せようと目論みました。 ちょうどその頃、Spot Fleetというものを使うと、 スポットインスタンスをお手軽に借りられるという話を聞いたので、 Spot Fleet + ECS で格安クラスターを作ってみよう!と手を出してみました。 (・・・もちろん、Fargateが東京リージョンで使えるようになったことは知っているけれど、スポットインスタンスの価格に負けてしまった・・・) AWS Fargate 東京リージョン サービス開始のお知らせ AWS Fargate で最大 50% の値下げを発表 ECS最適化インスタンスの更新問題 クラスターを作るだけなら、そう難しくはなく、インスタンス起動時にAmazon ECS-Optimized Amazon Linux AMIを使うだけです。 問題はこのイメージは定期的に更新される、ということです。 更新情報を流しているSNSトピックがあるので、これをサブスクライブしておくと、時たま更新通知が来ます。 Amazon ECS-Optimized Amazon Linux AMI の更新の通知のサブスクライブ この更新には機能追加はもちろん、セキュリティーフィックスも含まれているので、 なるべく早く新しいイメージに移行する必要があります。 移行は大まかに以下の手順で進めます。 新しいAMIイメージに更新した Spot Fleet を作成する 古いインスタンスに残っているタスクをいい感じに終了する(ドレイン) 突然殺すとユーザーにエラーが見えてしまうので、受付中のリクエストを捌き切ってから終了しないといけない ドレインが始まるとECSがタスク数を調整するために、新しいインスタンスにタスクをお引越ししてくれる ドレインが終了したら、古いインスタンスをシャットダウンする ここで問題になってくるのが「古いインスタンスに残っているタスクをいい感じに終了する(ドレイン)」の部分。 コンソールからポチポチするのも面倒なので、自動化したいところ。 しかし、いろいろとドキュメントをあさってみたのですが、「APIかawscliを叩く」「SNSとAWS Lambda をうまいこと組み合わせて頑張る」みたいな方法しか見当たらない・・・ しかもAWSの公式ブログ コンテナインスタンスのドレイン How to Automate Container Instance Draining in Amazon ECS Amazon ECS におけるコンテナ インスタンス ドレイニングの自動化方法 ・・・みんなどうやってるの・・・?

Jan 13, 2019 - 1 minute read - go golang mysql aws

IAM認証でAWS RDSへ接続するMySQLドライバを作った

AWS RDS には IAM 認証を使って接続する機能があります。 MySQL および PostgreSQL に対する IAM データベース認証 IAM 認証情報を使用して Amazon RDS への接続をユーザーに許可する方法を教えてください。 これを使って接続するGo言語のSQLドライバを書いてみました。 https://github.com/shogo82148/rdsmysql 使い方 IAMデータベース認証はデフォルトで無効になっているので、まずはこれを有効化します。 次に AWSAuthenticationPlugin を認証方式に指定して、新しいユーザーを作りましょう。 IAM データベース認証の有効化と無効化 データベースアカウントの作成 CREATE USER jane_doe IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'; 他のSQLドライバはimportするだけで使えるのですが、 rdsmysqlではAWSへの権限情報を設定しなければならない都合上、 sql.Register を自前で呼び出す必要があります。 とは言っても、AWS SDKがいい感じに設定ファイルとか環境変数とか読んでくれるので、 rdsmysql.Driver にAWSセッションを渡すだけです。 c := aws.NewConfig().WithRegion("ap-northeast-1") s := session.Must(session.NewSession(c)) d := &Driver{ Session: s, } sql.Register("rdsmysql", d) db, err := sql.Open("rdsmysql", "jane_doe:@tcp(db-foobar.ap-northeast-1.rds.amazonaws.com:3306)/") if err != nil { log.Fatal(err) } defer db.Close() あとは通常のMySQLドライバとして呼び出すだけです。 go-sql-driver/mysql のラッパーになっているので、 DNS等の書き方はこれに準じます。 認証部分は rdsmysql がやってくれるので、パスワードは空でOKです。 パスワードの管理から開放されて楽ですね!

Dec 16, 2018 - 3 minute read - perl aws lambda

AWS LambdaでCGIを蘇らせる

この記事は Perl Advent Calendar 2018の15日目の記事です。 (キリの良いところまでできたのと、記事が書かれていなかったので代打投稿) Custom Runtime のリリースにより、AWS Lambda 上でPerlが動くようになりました。 PerlをAWS Lambdaで動かす 次は AWS Lambda + CGI でサーバーレスだな... — Ichinose Shogo (@shogo82148) 2018年12月8日 ということで、やっていきましょう。 できたもの 動かすのはもちろん、 CGIアクセスカウンター 。 なんと嬉しいことに、最近になって WwwCounter の新バージョン(Ver3.16)がリリースされ、 Perl 5.26 に対応しました! 2018-11-11 perl 5.26に対応。(Ver3.16) 更新履歴によれば一つ前の Ver 3.15 のリリースは2003-03-23なので、なんと15年ぶりのアップデートです。 杜甫々さんの AWS Lambda で動かしてくれ!! という声が聞こえてきそうですね・・・!!! 動いたーーーー!!!! 実装はこちら AWS::Lambda ちなみにWwwCounterのアップデートはPerl 5.26で「@INCからカレントディレクトリが削除」された件への対応だと思います(コミットログがないので予想)。 第46回 Perl 5.26で変わること(1) - Perl Hackers Hub 実装説明 「そもそもCGIってなんだ?」っていう人も多くなってきたと思うので、そこらへんの歴史の話にも軽く触れます。 この辺の歴史をリアルに体験したわけではないので、誤り等あればご指摘ください。 CGIとは Common Gateway Interface の略で、 WebサーバーとCLI(Command Line Interface)アプリケーションのやり取りの方法を決めた規格です。

Nov 30, 2018 - 2 minute read - perl aws lambda

PerlをAWS Lambdaで動かす

AWS Lambda で Custom Runtime が発表されました! 新機能 – AWS Lambda :あらゆるプログラム言語への対応と一般的なコンポーネントの共有 New for AWS Lambda – Use Any Programming Language and Share Common Components AWS Lambda Now Supports Custom Runtimes, and Enables Sharing Common Code Between Functions Custom Runtime により好きなプログラミング言語でLambda関数を書くことができ、 いくつかの言語についてはAWSおよびパートナーから bootstrap が提供されます。 提供される言語にCOBOLが入って話題になっていますが、 当然ながら(?)Perlはありません。 Custom Runtimeは shell script でも書ける簡単なものなので、Perlでも書いてみました。 Perl in AWS Lambda 以下のスクリプトを bootstrap という名前で保存します。 #!/usr/bin/env perl use utf8; use warnings; use strict; use lib "$ENV{LAMBDA_TASK_ROOT}/local/lib/perl5"; use Furl; use JSON; my $furl = Furl->new; my ($handler, $function) = split /\.

Nov 22, 2018 - 2 minute read - go golang

Goのnil,true,falseは変数名に使えるという話

@Linda_pp さんのツイートをみて Go 言語の nil って NilLit じゃなくて Ident "nil" としてパースされるのか.それで気付いたけど nil := 42 みたいに普通に変数宣言できる(unused でエラーになるけど) — ドッグ (@Linda_pp) 2018年11月22日 なるほど、これは面白い。 と少し遊んでみたメモ。 言語仕様にある通り、Goのキーワードは以下の25個です(Go1.11.2)。 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var この一覧に nil や true, false は入っていません。 これらは builtinという扱いになっており、識別子として利用可能です。 そのため、変数名等に利用可能というわけですね。面白い。 package main import ( "fmt" ) func main() { nil := 42 fmt.Println(nil) // Output: // 42 } 以下、色々遊んでみた例。

Sep 24, 2018 - 3 minute read - go golang php

PHPer向けGoのJSONデコーダーを作った

必要に迫られて作りました。 PHPでエンコードしたJSONをいい感じにデコードしてくれるGoのパッケージです。 shogo82148/go-phper-json 背景 さて、PHPerの方々には当たり前のことかもしれませんが、PHPの言語仕様について少しおさらいです。 それがどうしてGoで問題になるか見ていきます。 PHPのarray問題 PHPはとても便利なプログラミング言語なので、配列を扱うことができます。 ここでPHPの配列のマニュアルを読んでみましょう。 http://php.net/manual/ja/language.types.array.php PHP の配列は、実際には順番付けられたマップです。マップは型の一種で、 値をキーに関連付けます。 この型は、さまざまな使い道にあわせて最適化されます。 配列としてだけでなく、リスト (ベクター)、 ハッシュテーブル (マップの実装の一つ)、辞書、コレクション、スタック、 キュー等として使用することが可能です。 PHP の配列には他の PHP 配列を値として保持することができるため、 非常に簡単にツリー構造を表現することが可能です。 (強調部分は筆者によるもの) 重要なことなのでもう一度。 配列としてだけでなく、リスト (ベクター)、 ハッシュテーブル (マップの実装の一つ)、辞書、コレクション、スタック、 キュー等として使用することが可能です。 他の言語でリスト、ハッシュテーブル、辞書等と呼ばれているものは、PHPにおいてはいずれも配列です。 PHPにとっては、整数を添字にしているか、文字列を添字にしているかの違いでしかありません。 (PHP7.xから整数が添字の場合に最適化が入るようになったらしいけど、大きな挙動の変更はないはず) そのため、以下のスクリプトは true を返します。 <?php $a = array("apple", "banana"); $b = array(0 => "apple", 1 => "banana"); var_dump($a == $b); // bool(true) この仕様のため、JSONにエンコードすると最初は配列だったのに、 処理を進めていくうちにうっかり文字列のキーを作ってしまって、 JSONのオブジェクトに変わってました、ということが起こりえます。 Goにおいて両者は全く違う型なので、デコードの際に非常に困ります。 <?php $a = array(1, 2, 3); print json_encode($a); // [1,2,3] $a["foo"] = "bar"; print json_encode($a); // {"0":1,"1":2,"2":3,"foo":"bar"} このような悲劇を防ぐために、 JSON_FORCE_OBJECT というオプションがあるのですが、 オプションの名前通りに全部JSONのオブジェクトになってしまいます。 この要素だけJSONの配列にして欲しい!といった細かな操作はできません。