「Amazon S3のストレージ料金を無料にする裏技」改

こちらの記事を読んで「なるほど、確かに面白いな」と思いました。

kusano-k.hatenablog.com

特に気になったのはこの部分。まだまだいけるんじゃないかと。

ファイルの取り出しのLISTは1000件まとめて取得できるので、無視できる。 PUTリクエストは0.0047USD/1,000回。 1回、1バイトあたり6.3172×10-9USD。 ストレージ料金の「GB」が10003なのか10243なのか分からない。 10243とすると、6.783USD/GB。 ということで、3,392月=283年以上保存するならば、S3 Glacier Deep Archiveに保存するよりも、ファイル名にエンコードしたほうがお得💰💰💰

Amazon S3のストレージ料金を無料にする裏技 - kusano_k’s blog

追記(2022/01/28 11:00)

職場の方から指摘をもらって、AWSの公式FAQに

1 か月に請求されるストレージの量は、月全体を通じて使用される平均ストレージです。これには、お客様の AWS アカウントで、お客様が作成したバケット内に格納されるすべてのオブジェクトデータやメタデータが含まれます。

Amazon S3 のよくある質問

という記述があることを知りました。メタデータもストレージ使用量の課金対象のようなので、この手法は残念ながら(?)無料ではなさそうということが発覚しました。
ということでブレイクスルーは起きませんでした。残念🥺🥺🥺

ブレイクスルーを起こしたい💰💰💰

3,392月=283年以上保存するならば、S3 Glacier Deep Archiveに保存するよりも、ファイル名にエンコードしたほうがお得💰💰💰

Amazon S3のストレージ料金を無料にする裏技 - kusano_k’s blog

これを超える方法が何かないか考えてみたところ、思いついたのでご紹介します。

docs.aws.amazon.com

Amazon S3にはメタデータという自由記述欄があります。メタデータには2種類あり、「System-defined object metadata」と「User-defined object metadata」があります。

System-defined object metadata

System-definedなメタデータは使えるキーの名前が決まっていて、自由に追加はできません。試しに適当にオブジェクトをアップロードし、メタデータを確認しました。

{
    "AcceptRanges": "bytes",
    "LastModified": "2022-01-27T13:14:34+00:00",
    "ContentLength": 0,
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "text/plain",
    "Metadata": {}
}

余計なキーを増やすと容量を消費してしまうので追加しないとして、この中で唯一任意の文字列が設定できるのは ContentType 一択のようです。

AcceptRanges, ETag はドキュメントにはメタデータとして記載されていないので、容量は消費しなさそうです。keyとvalueの合計なので、 LastModified で37byte消費、ContentLength で14byte消費といったところでしょうか。 ContentType のキー名は11byteです。

System-defined object metadataは2KBまで保存できるようなので、 2048 - 37 - 14 - 11 = 1986byte 使えそうです。引用元記事同様Base64エンコードするとすれば 1938 / 4 * 3 = 1489byteですね。

User-defined object metadata

User-definedなメタデータは使えるキーの名前は x-amz-meta- ではじまればなんでもいいようです。ここで文字数を消費したくないので x-amz-meta-0 とでもしておきましょう。 x-amz-meta-0 のキー名は12byteです。

User-defined object metadataは2KBまで保存できるようなので、 2048 - 12 = 2036byte 使えそうです。引用元記事同様Base64エンコードするとすれば 2036 / 4 * 3 = 1527byteですね。

$ aws  s3api head-object --bucket bucket --key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2022-01-27T13:36:57+00:00",
    "ContentLength": 0,
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "Metadata": {
        "0": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
    }
}

AWSコンソール上の見た目もよくわからない感じになっている。

f:id:kuro_m88:20220127224241p:plain
aws console上の見た目

気になるお値段

list-objects-v2 APIではメタデータが取得できないので、head-object APIでオブジェクトごとにリクエストしないといけない。この操作にかかる料金は1回あたり0.0000004USDで、誤差ということで考えないことにする。

1個のオブジェクトのキー名に、(1024-32)/(4/3)で744バイト分のデータを詰め込める。

Amazon S3のストレージ料金を無料にする裏技 - kusano_k’s blog

ということだったので、 オブジェクトのキー: 744 byte, システムのメタデータ: 1489byte, ユーザのメタデータ: 1527byte, 744 + 1480 + 1527 = 3751byteまで保存できそう。3751 / 744 = 5.04倍保存できるので、

3,392月=283年以上保存するならば、S3 Glacier Deep Archiveに保存するよりも、ファイル名にエンコードしたほうがお得💰💰💰

Amazon S3のストレージ料金を無料にする裏技 - kusano_k’s blog

3392ヶ月 / 5.04 = 673ヶ月 = 56年以上保存するならば、S3 Glacier Deep Archiveに保存するよりも、ファイル名にエンコードしたほうがお得!!💰💰💰

M1 MacでLima + Dockerの環境構築

Docker Desktopが一定条件で有償化*1されるので、脱Docker Desktopしてみた。 意外とそんなにハマることもなく環境構築に成功して、Docker Desktopを使っていた時代とほぼ変わらない開発体験が得られました。

Limaを選んだ理由

  • lima コマンドを打つだけでデフォルトのVM(Ubuntu)のシェルに入れる(もしくはlimaの後ろに付加した文字列がそのままコマンドになる)
  • 標準設定でホストとネットワークを共有する(dockerでportをexportしたらlocalhost:1234でアクセスできる)
    • --net=host が使える
  • 標準設定でMacのホームディレクトリがVMにマウントされてる(嫌だったら設定変えられる, sshfsでマウントされてるだけ)

環境

  • M1 Mac Book Pro
    • Intelでもいけるはず

Lima側の構築

  • これがDocker Daemonを実行するVM(Ubuntu)
  • コマンドは全てMacのターミナルで入力
$ uname -a
Darwin my-m1-mac 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000 arm64

$ brew install lima

$ limactl start
# ディスク容量やCPUなど、設定をカスタマイズしたい場合は好みで変える。特に何も変えなくてもOK

# 起動確認
# limaコマンドだけ打つとシェルログインできます
$ lima uname -a
Linux lima-default 5.13.0-22-generic #22-Ubuntu SMP Fri Nov 5 13:22:27 UTC 2021 aarch64 aarch64 aarch64 GNU/Linux

$ lima sh -c 'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg'
$ lima sh -c 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null'

$ lima sudo apt-get update
$ lima sudo apt-get install docker-ce docker-ce-cli containerd.io

# 動作確認
$ lima sudo docker run hello-world

# Macと通信できるように設定
$ lima sudo sh -c 'echo "{\"hosts\": [\"tcp://127.0.0.1:2375\", \"unix:///var/run/docker.sock\"]}" > /etc/docker/daemon.json'
$ lima sudo mkdir -p /etc/systemd/system/docker.service.d/
$ lima sudo sh -c 'echo "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd" > /etc/systemd/system/docker.service.d/override.conf'

$ lima sudo systemctl daemon-reload
$ lima sudo systemctl restart docker.service

Mac側の構築

  • dockerのクライアントをインストールする
  • コマンドは全てMacのターミナルで入力
$ cd ~
$ mkdir bin

# Intel Macの場合
$ curl -o docker.tgz https://download.docker.com/mac/static/stable/x86_64/docker-20.10.9.tgz

# M1 Macの場合
$ curl -o docker.tgz https://download.docker.com/mac/static/stable/aarch64/docker-20.10.9.tgz

$ tar xvf docker.tgz
$ mv docker/docker ~/bin/docker
$ rm docker.tgz
$ rm -rf docker/

# .bashrcや.zshrcのPATHに~/binを通す

# .bashrcや.zshrcで
# export DOCKER_HOST='tcp://127.0.0.1:2375'
# を追記する

$ docker version
Client:
 Version:           20.10.8
 API version:       1.41
 Go version:        go1.16.6
 Git commit:        3967b7d
 Built:             Fri Jul 30 19:55:20 2021
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.12
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.12
  Git commit:       459d0df
  Built:            Mon Dec 13 11:43:40 2021
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          v1.5.8
  GitCommit:        1e5ef943eb76627a6d3b6de8cd1ef6537f393a71
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba2
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

# 動作確認
$ docker run hello-world

docker-composeも入れておく

# Intel Macの場合
$ curl -Lo docker-compose https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-darwin-x86_64

# M1 Macの場合
$ curl -Lo docker-compose https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-darwin-aarch64

$ chmod +x docker-compose
$ mv docker-compose ~/bin/

普段の使い方

VMを開始する時

$ limactl start

VMを停止する時

$ limactl stop

もっと使いこなすには

Cloudflareのアカウントを勝手に開設され、Webサイトやドメインが乗っ取られうる状態になった話

タイトルのとおり、自分のメールアドレスを使ってCloudflareのアカウントを第三者に勝手に開設されました。何が起きたのかとその後の対応についてまとめてみます。

※ Cloudflareのアカウントを第三者に勝手に開設されるだけでは即座に何かしらのサイトやドメインが乗っ取られるわけではありません。

目次

時系列

何が起きて、何をしたのか、簡単に時系列でまとめました。

時刻(JST) 事象
9/26 22:54 何者かにCloudflareのアカウントを勝手に作成される
9/26 22:54 Cloudflareから"Please verify your email address"というメールが届く
9/26 22:57 何者かにCloudflareのGlobal API Keyを勝手に生成される
9/26 22:57 何者かにCloudflareのGlobal API Keyを勝手に閲覧される
9/26 22:57 何者かにCloudflareのGlobal API Keyを勝手に閲覧される
9/26 22:57 何者かにCloudflareのGlobal API Keyを勝手にローテートされる
9/26 23:?? Cloudflareからの身に覚えのないメールに気づき、フィッシングを疑う
9/26 23:?? Cloudflareのアカウントの存在を確かめる
9/27 00:03 自分でCloudflareのパスワードをリセット(全ログインセッションが無効化される)
9/27 00:04 自分でCloudflareにログインしなおす
9/27 00:?? 自分でCloudflareのAudit Logを閲覧し事態を把握する
9/27 00:34 自分でCloudflareのGlobal API KeyとOrigin CA Keyをローテートする

何者かにCloudflareのアカウントを勝手に作成された

f:id:kuro_m88:20210927004738p:plain
突然の身に覚えがないemail verification通知

こんなメールが突然届きました。CloudFlareの操作はおろかブラウジングもしていなかった時間帯だったので、明らかに怪しいメールです。 このリンクをクリックすると何が起きるのかもよくわからなかったので、警戒しつつ次になにをしようか考えます。( 身に覚えがないメールのリンクは絶対にクリックするのはやめましょう )

このメールを受け取ったメールアドレスは(当たり前ですが)自分のメールアドレスで、この記事では仮に admin@example.com とします。

Cloudflareのアカウントが実在するのか確認する

admin@example.com でCloudflareのアカウントを開設した記憶はなかったため、実在するのか確認しました。 アカウントの存在確認は簡単で、 admin@example.com のメールアドレスでアカウントを新規作成しようとすればよいわけです。

f:id:kuro_m88:20210927010135p:plain
アカウントがすでに存在するらしい

開設した覚えのないアカウントがすでに存在しているので、本当に何者かにアカウントを勝手に作成された可能性が高いことがわかりました。

パスワードリセット

すでにアカウントは存在していますが、メールアドレスは自分のものなので、パスワードリセットは可能です。

パスワードを忘れた時の手順でリセットをかけ、アカウントをひとまず自分の管理下に置くことにします。

Audit Logを見る

f:id:kuro_m88:20210927010652p:plain
CloudflareのAudit Log

CloudflareにはAudit Log(監査ログ)機能があり、Cloudflare上で行われた操作のログがのこっています。やはり身に覚えがない時間帯にアカウントが作成されたようです。

アカウントの作成だけでなく、 APIキーの作成と閲覧 もしているようですね。

f:id:kuro_m88:20210927010908p:plain
犯人のIPアドレス

犯人のIPアドレスもわかりました。実際にはただのproxyかもしれませんが。

whois情報の照会ができるwebサイトで見てみると、アルゼンチンのISPに割り当てられているIPアドレスのようです。明らかにおかしい。

f:id:kuro_m88:20210927011307p:plain
アルゼンチンのIPアドレス

APIキーをローテートする

Audit Logより、APIキーが作成され、閲覧された形跡があることがわかりました。 そのあと再度ローテートされているのは何がしたかったのかはよくわかりませんね…。

ローテート後、新しいAPIキーを閲覧した形跡はないためたぶん犯人は最新のAPIキーを知らないのでは?という気はするものの、ローテートすると同時に新しいAPIキーが閲覧できる仕組みだったら怖いので、再度自分でAPIキーをローテートしました。

Audit LogがないサービスだったらAPIキーを作成し閲覧されたことに気づくのは難しいので、 何をされたのかわからない場合はアカウントを削除する のがこれ以上の被害を防ぐ上で一番いいと思います。

今回は興味本位で調査に使いましたが、使わないアカウントを保持し続けても仕方がないのでどのみち削除するのがよさそうです。

攻撃者は何がしたかったのか(推測)

ここからは自分の推測でしかないですが、犯人は何がしたかったのか考えてみました。

どこからメールアドレスを収集してきたのか

まずどこからこの実在するメールアドレスを収集してきたのかですが、たぶんGithubのコミットログなどから拾ってきたのかなぁと思います。

Cloudflareのアカウントを乗っ取ってなにがしたかったのか

メールアドレスの情報源がGithubだったと仮定すると、そのメールアドレスの持ち主はソフトウェアエンジニアである確率が高そうです。 となるとCloudflareを知っている確率は高いので、Cloudflareからemail verificationのリンクが来ても不審に思わなかったり、ついうっかりクリックしてしまう可能性はあります。

忘れるくらい時間が経った頃に自分がCloudflareを使おうとしたとします。正規のユーザ(自分のこと)はログインできないことに気づき、パスワードリセットをかけてCloudflareを利用しますが、APIキーを悪意のある第三者に盗まれていたことに気づくことは難しいでしょう。

そのCloudflareのアカウントを使ってCDNの設定やDNSの管理をしはじめると、 悪意のある第三者はそのCDNDNSを操作し放題 になるでしょう。 これが犯人の目的かな?と想像しています。

教訓

  • 身に覚えのないemail verificationが届いても、絶対にクリックしない
  • email verificationが行われていないアカウントであっても、何をされるかわからないので、アカウントを勝手に作成された場合は正規の方法で取り返す
  • 乗っ取られたアカウントは取り返した上で削除するか、audit logを見て何をされたのか把握する

たまたま不審に思ったので対処することができましたが、怖いですね。

サイバーエージェントでの6年間と、次にやること

前回の記事から2.5年くらい経過したので近況を書いてみます。

kurochan-note.hatenablog.jp

そろそろ何をやってきたのか忘れそうなので振り返っておくのと、今思っていることについて雑多に書き出しておきます。 今回はちょっと長めなので目次を作っておきました。

目次

  • サイバーエージェントでの6年間
  • 給料の話
  • 暇にさせてくれない上司と会社
  • 技術選定の自由という名の動物園
  • 採用には全力を尽くす
  • 挑戦した敗者にはセカンドチャンスを
  • 次は何をやるのか
  • さいごに

サイバーエージェントでの6年間

既に細かいことをわすてしまっているような気がするので印象的な出来事だけ列挙してみました。

2015年

  • 飛び交う言語が独特すぎてそれが面白かったのでメモを取り続けて公開したらちょっとバズった

kurochan-note.hatenablog.jp

  • 突然アメリカで約2ヶ月間働いたりしてた
  • 1メンバとして開発ができるようについていくのに必死

2016年

  • アドテクコンペというインターンを運営した
    • かなりうまくいったので改善しつつ、これを元にしたものが年2回くらいのペースで開催されるように
    • こんな感じのやつ

developers.cyberagent.co.jp

  • 他に何をしていたかあまり覚えていないかも…?
  • AWSのre:Inventに行かせてもらった

2017年

  • 広告の画像をユーザによって違うものを動的に生成し、さらにできるだけ低遅延で配信するというのをやっていた

Dynalystにおける動的な画像生成 - Speaker Deck

  • プロダクトのコードのビルドが遅いことにイライラしていたのでとにかく高速化したくてひたすらキャッシュしていた気がする

Scalaプロダクトのビルド高速化 - Speaker Deck

  • GoogleのMaglevの論文を読んでめっちゃすごいと思い、ネットワークに再び興味を持った

Maglev: A Fast and Reliable Software Network Load Balancer

2018年

2019年

  • 開発責任者というポジションになった
  • 「エンジニアブログを書こう月間」を企画してチームメンバ全員で1ヶ月間毎営業日ブログを書いた
  • Scala MatsuriのWi-Fiスポンサーを担当し、好き放題やったインフラ環境を構築した

2020年

  • 事業部に配属されてきた新卒向けの技術研修をがっつりやった
  • Slack Enterprise Gridを会社全体に導入した
  • GitHub Enterprise Cloudを会社全体に導入した
  • Snowflakeを使ったデータ基盤を構築した
  • Envoyを導入してモノリシックなサービスを分離できるようにした

2021年

  • AppleのATTどうするか問題
    • ラッキングまわりで嫌われがちな広告ですが、あくまでもユーザに対して誠実な商品を作った上で効果の出る商品づくりをしていこうという意思決定ができたのは良いことだった
  • 悩みが出てきた
  • 4月以降の話は最後に

給料の話

だいたいこういう系の記事は失敗談と給料の話がウケると相場が決まっていますね。

入社してから給料は上がっていますが、上がる時もあれば、あまり上がらない時もあったという感じです。頑張るタイミングと成果がでるタイミングというのは必ずしも一緒じゃないので、評価と自分の実感に悩むこともありました。

一生給料が上がり続けたらとんでもない額になるはずですが、さすがにそんなことはなく、給料を貰う側(=社員)である限りどこかで頭打ちになるのは分かっていて、今がそのタイミングかなぁという感覚もあります。

一緒に働くひとを採用する側になり、年収提示でオファーがくるサービスを試しに使ってみた時期もありましたが、お互いによく知らない状態で攻めたオファー金額を提示することは難しいということも分かりました。そういった体験もあり、転職しただけで爆上がりすることもないかなぁと思っています。年収をあげたいだけだったら副業したほうがいいかもしれないですね。

お金の話はpublicなところでは書きづらいですね。この会社に転職を考えていて、話を聞いてみたいという方がいらっしゃればご連絡ください。具体的な数字は触れませんが、主観的にみた雰囲気はお伝えできるかもしれません。

暇にさせてくれない上司と会社

一言も飽きたと言ったことはないのですが、飽きそうになるタイミングでだいたい突然何かが振ってきます。

入社当時はほぼ技術にしか興味がなく、広告系の部署を志望した理由も低レイテンシで高トラフィックなシステムを作る必要があるので、バックエンドエンジニア的に面白そう、当時はコンテナ技術(LXC, Docker)に興味を持っていて、これから入れていきたいという話を聞いていたのでここならやれそうだと思ったためでした。

実際配属されて働き始めると、チューニングだとか新しい技術の導入だとかをやる以前に、機能追加やビジネスロジックの実装といった部分の仕事がこなせないレベルでした。自分のプログラミング能力や、既存のコードを読み解いて方針を考える能力が低かったのもあるとは思いますが、どこかでkumagiさんのツイートのような事に気づいたような気がします。

プロダクト開発をしている限り、プロダクトの理解がなければ何を実装すべきかもわからないし、チューニングをしたところで嬉しいのかもわからない、どこでお金を作っているかも分からなければ優先度の判断もできないということがわかりました。これじゃあつまらないじゃないかと思ったこともありましたが、同時にビジネス課題を解決する形でエンジニアリングが生きてくる場所を見つけられれば誰にも文句を言われないし、やはり技術で勝負したいのでどこかで一発当ててやろうという気持ちになりました。

チームの開発スタイルにも慣れて、ある程度与えられたタスクをこなすことは出来るくらいにはなったかな?という時から上司からはビジネス面の観点も持ってほしいと常に言われていた気がします。 商品の機能のすりあわせや事業としてのチャンスを探るような場にも呼ばれ、当時の気分としてはビジネスの話よりコードを書いている方が楽しいんだけどなぁ。。という感じでしたが、こういう場での話をずっと聞いているうちに自分が頑張って作ったはずなのにたいして使われなかったり、インパクトがなかったり、逆にそんなに頑張ったつもりではないのにインパクトが出せたりという部分の感じ方がズレていたことが分かってくるようになりました。このあたりから自己満足ではなく意味のある開発がしたいと思うようになり、事業自体に自分がどう影響を与えられるのかという部分にも興味を持ち始めた気がします(遅い)。

一方でAWSGCPといったクラウドは事業を作るという点においてはスピード感が出せて最高ですが、技術的には自分たちで面倒を見る必要があるものが少ない分、つまらなくなってきたので趣味で物理サーバに手を出しはじめたりしました。

そして落ち着いてきたと思ったら開発責任者というポジションを任され、あまり考えてこなかったメンバの評価や育成、開発チーム自体をどうしていくかみたいな部分で頭をかかえはじめました。

2年くらい開発をやりつつ、マネジメント的な業務をやったあとはチーム内で役割分担するようになりました。

ちょっと余裕が出てきたな、と思ったときに面白そうな話に乗っかってしまい、会社全体向けにSlack Enterprise GridとGitHub Enterprise Cloudを導入する仕事をしました。 もともとは部署やチーム単位でバラバラにSlackやGitHubを契約していたのですが、部署をまたいだ連絡や情報の共有がしづらいという課題感を持った各部署の人たちが有志で集まるところからスタートし、Enterprise契約に集約してセキュリティ的な統制を担保しつつ情報共有のハードルをかなり下げることができるようになりました。他部署の方々と各所調整してまわったり、セキュリティチームに助けてもらったりした結果実現できたのですが、調整して組織全体を動かすみたいな仕事の仕方を学びました。

等々あった結果いい意味であまり暇になることはありませんでした。

採用には全力を尽くす

会社のミッションステートメントのうちの一つです。

これは本当にいい文化だと思っていて、特に新卒採用は文化として定着していると思います。 そういう環境で採用された人が多いので、育成もトレーナーが新卒に合わせてそれぞれで考えて動いているように思います。

自分もそうやって採用してもらって育ててもらったので今があります。 自分の所属管轄のボス(役員)の内藤さんの記事は毎年何かしらの形でシェアしています。

ameblo.jp

面接官もやっているのですが、採用方針や評価基準まわりで人事や他部署のエンジニアと話し合うことも多いように思います。部署によって微妙に欲しい人物像が違ったり、事業の変化も多いのでなかなか決まらなかったり擦り合わないこともありますが、(喧嘩しているわけではないのですが)納得が行くまで譲らない姿勢でみんな取り組んでいるように思います。

技術選定の自由という名の動物園

うちの会社はよく言えば技術選定は自由です。各自に裁量があります。

チーム内で合意さえ取れていればどんな技術だって取り入られれると思います。 プロダクトの経営方針についてはその上の経営層から指示がくることもあるとは思いますが、技術面の方針で上から指示がくることは見聞きしたことはありません。

会社紹介でベンチャーの集合体のような会社です、と表現されていることもあって、実際にそのようなイメージで間違いないと思います。 ただ、5000人を超える社員が所属していて、そのうちエンジニア職が1000〜1500人くらいいて、時価総額が1兆円を超えることがあるような会社が世の中で想像されるようなベンチャーそのものかというとちょっと違うんじゃないかなと思います。

www.nikkei.com

ベンチャー企業のような勢いとマインドを持ち続けるのは必要ですが、これだけ大きな会社なので必ずしもベンチャーと同じ戦い方をする必要はないのでは?と思っています。

新しいプロダクトやシステムを立ち上げるときに、ゼロから開発するのは非常に楽しくて、自身のスキルアップにも繋がるためモチベーションも高くなりますが、すこし引いた視点で見ると同じことを繰り返していたり、非効率に見えることもあるかと思います。

抽象的な言い方をすると、技術力だったり組織サイズが横並びでスケールすることはできるものの、技術力や開発した資産を積み上げることでの「高さ」を作るのには向いていないような気がしています。

それに対して何も動きがないということはなく、各部署で横断組織を作る動きはあったりしますが、うちの会社っぽい事例というのはまだ確立されていないように思います。 個人的にはここは大きなチャンスポイントだと思っていて、何かしら取り組んでいきたいと思っています。

他の人が言っているのを聞いたことはありませんが、こういった背景や、かといって誰の手にも負えないくらいバラバラということもなく、会社という体を維持できる程度には統制は取れているという意味を込めて個人的には裁量とか自由という言葉と合わせて「動物園」という比喩をよく使っています。

挑戦した敗者にはセカンドチャンスを

こちらも会社のミッションステートメントのうちの一つです。

「信頼残高」という社内でよく使われる言葉があり、役員の曽山さんは「期待を超えると残高が増え、下回ると残高が減る」というふうに解説しています。

ameblo.jp

信頼残高を使って大きな仕事をやったという実感はまだなくて、まだうまく立ち回ろうとして信頼残高を貯金しているような気がしています。

絶望するくらい派手に失敗してしまった人にしかこの言葉の意味はわからないんだろうなぁと想像していて、6年働いてもまだこの言葉の意味はピンときていないので、リスクを取った挑戦と言えるレベルのことはやっていかないといけないなと思っています。

6年間同じチームで働いていると考え方が硬くなってしまうというか、煮詰まりがちです。ドメイン知識も身についてきた分、リスクを判断したり、守りを固めることは強みになってきたかもしれません。 ただ、目指している方向性としてはあくまでも成長しつづけることなので、守っているだけではあまり貢献ができている実感が沸かなくなってきます。このあたりは最近の悩みでした。

挑戦やチャンスに対してスポットライトをあてて応援する文化がある一方で、失敗したときはその失敗についてしっかり反省, 共有をする必要もあると思っています。勢いがある感じだけ出してても必ず足元をすくわれて、無駄な失敗をするので必要な反省というのは引き続きやっていこうと思います。

次は何をやるのか

この記事が退職エントリーなのか在職エントリーなのかでいうと、今回も在職エントリーでした。 引き続き今の会社で働いていきます。

新しい取り組み(?)として、入社7年目にして初めて異動してみることにしました。

事業部は変わらないのですが、小売DXという部門で働きます。 小売というのは生産者(メーカーなど)や卸売業者から商品を仕入れ一般の消費者に販売する業種です。 スーパー、コンビニ、家電量販店、ドラッグストアなどを思い浮かべてもらうとよさそうです。

日本の小売業の販売額は145兆円(2019年)ほどあるようです。

www.meti.go.jp

日本の広告費は6兆円程度(2020年)のようなので、市場規模がかなり違いそうです。

www.dentsu.co.jp

インターネット広告市場でインターネット広告の商品そのものを作っていた時と違い、直接的に小売業をやるわけではないので、事業の収益化の方法も今までと変わってくるはずです。この市場を取りに行く、というよりはこの市場に対して新しい入り方をする、という解釈のほうがしっくりくるのかなという印象です。ターゲットにする市場が大きければ何か影響を与えたときのチャンスも大きそうですね。

これから小売DXという部門で色々立ち上げていきます、というフェーズなのであまりたくさん事例は出ていませんが、最近出たリリースだと

www.cyberagent.co.jp

こういうのがあるようです。インターネット広告が強みの会社なのでデジタル広告は絡んできていますが、それ以外のオンライン(EC, アプリなど)とオフライン(実店舗)を組み合わせたデータ基盤を作って様々なマーケティング活動ができる販促プラットフォームを作る、というのは新しい取り組みのように思います。

ほかにも既にデジタルサイネージを活用したプロダクトがあって社内でサイネージ端末と連携するシステムを作っているチームもありますが、エンジニア組織を持っていて企画に合わせた内製ができることや、インターネット広告をリアルタイムに取引するシステムを開発する上でのデータの扱いや大規模なデータ向けの分析基盤といった分野の知見は強みになるような気がします。 公式アプリのようなモバイルアプリの開発もやっていくようなので、メディア事業をやってきた企業としての強みも活かせるかもしれません。

出ている情報以外にも仕込み中の話がたくさんありますが、既存の大きな業界に対して単独で事業を立ち上げるわけではなく、様々な企業と提携するような形で事業を作っていくことが多くなりそうです。完全なゼロからの立ち上げでもなく、受託のように指示されたものを作るわけでもなく、自分たちの企画と実装力が肝になってきます。この取り組みがうまく行けば既存のWeb系企業とは違った新しい業態が作れると思うので面白いです。 エンジニア目線で言えば自分たちの強みだと思っているWebの技術がこの業界に対してどれだけ通用するのか、という部分で腕試しができるんじゃないかと思っています。意外とそんな簡単にはいかなさそうです。

こういう状態の部署に異動するので、まだ自分が具体的にどう動いていくのか決まっていません。 既に働いているメンバのやりとりを見たり、首を突っ込めそうな部分に突っ込んでみたりしたところ、まずは要件定義の部分に関わらせてもらって皆無なドメイン知識を補いつつ、インフラ〜バックエンドの開発をやり、最低限のセキュリティは死守する役割とかがいいのかなぁと思いました。

あと、どう考えても自分だけで手に追える規模の話ではないので、引き続き採用はやっていきます。一緒に働きましょう。 自分は他人があまりやらないようなところにチャンスを見出して成果を出すのが向いているんだろうなと思っているので、自分なりの動き方を見つけていく予定です。

さいごに

なんとなく思い立って勢いで書いてみました。数年後また振り返ってみようと思います。

ここまで読んでくれる方がどれくらい居るのかわかりませんが、最近採用サイトができたので、宣伝もしておきます。

www.cyberagent.co.jp

バックエンドエンジニア、フロントエンドエンジニア、インフラエンジニア(パブリッククラウド中心)、iOS, Androidの職種を募集しています。自分のつながりがある人はエンジニアが多いとは思いますが、ビジネス職も募集しています。

もし少しでも興味を持ってくれる方がいらっしゃったらDMをください。

ここで書かなかったようなことが話せるかもしれませんし、聞きたい話をしてくれそうな人を紹介することもできるかもしれません。

twitter.com

ということで、社会人7年目も元気にやっていこうと思います。