新しい環境にdotfilesをワンライナーで反映させる

はじめに

こんにちは、カンムでバンドルカードの機械学習を担当しているfkubotaです。テックブログ初参加なので今回はライトな内容で投稿させていただきます。イケイケ機械学習記事はいずれ...

この記事では、最近ちょっとだけ改善した dotfiles の管理について紹介したいと思います。
dotfiles とは、ホームディレクトリ($HOME) 下にある、.vimrc, .bashrc などの設定ファイル群を指します。
最終的には、コマンド1つでこのdotfilesが新しい環境に反映されます
魔法のコマンド:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/fkubota/dotfiles/master/install.sh)"

このコマンドでdotfilesが反映されると、
これが f:id:kanmu-tech:20210520111556p:plain

こうなります f:id:kanmu-tech:20210520111616p:plain

結論だけ見たい方は、方法紹介 から見ると良いと思います。

  • こんな人が想定読者
    • dotfiles 管理しなきゃと思っているけど、何もしてません...TT
    • dotfiles をまとめたリポジトリはあるよ。でも新しい環境に反映させるのは少し面倒...。

上記に該当する人に有用な記事になるように頑張って書きます。

参考記事

基本的にはこの記事を参考にしています。
この記事の作者ほどヘビーユーザではない&もう少し気軽に使いたいのでちょっとコードを変更しています。

dotfilesを管理するモチベーション

機械学習をやっている人は、新しい環境で作業を行うという経験が多いのではないでしょうか?
会社の計算サーバーにssh接続して使うとか、GCPAWSのマシンを借りるとか。その都度、そこで自分の開発環境を構築するはずです。僕の場合であれば、vim, tmux, fish のオレオレ設定を普段使っているので新しい環境でもそれを構築しています。

僕自身、以前はめちゃくちゃしんどい管理の仕方をしていました。
歴史としてはこんな感じです。

  1. 新しい環境で作業するたびにdotfilesをコピペ
    • この管理だとどの環境が最新状態なのかわからなくなります
  2. gitで管理して、シンボリックリンクを作る
  3. シンボリックリンクを行うシェルスクリプトを作成
    • これで大分楽になった
  4. git cloneからシンボリックリンク作成までを ワンライナー
    • NOW!!

方法紹介

まずは、dotfilesリポジトリgithubで作成してください。
ちなみに僕のリポジトリこちら

今回は簡単のために、.vimrc のみを管理対象とします。
dotfiles リポジトリ内に、.vimrc を作成します。

touch dotfiles/.vimrc

次に、シンボリックリンクを行うためのシェルスクリプトをdotfilies下に作成します。
ファイル名は、install.sh としてください。
install.sh の中身は以下のようにします。

DOT_DIR={dotfilesリポジトリをクローンするディレクトリ}

# clone
git clone https://github.com/{your account name}/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

上記の {dotfilesリポジトリをクローンするディレクトリ} と {your account name} をそれぞれ適切な値に設定してください。
僕の場合であれば、

DOT_DIR="$HOME/Git/dotfiles"

# clone
git clone https://github.com/fkubota/dotfiles.git ${DOT_DIR}

# link
ln -sf $DOT_DIR/.vimrc ~/.vimrc

となります。これで準備完了です。
このスクリプトを実行すれば、DOT_DIR で指定したディレクリにdotfilesリポジトリがクローンされ、.vimrcシンボリックリンクされます。lnコマンドに-fオプションが指定されているので、すでにある場合に上書きされてしまうので困る場合は外してください。

あとは、ワンライナーを叩くだけ!! です!
どこのディレクトリ下でもいいので、

bash -c "$(curl -fsSL https://raw.githubusercontent.com/{your account name}/dotfiles/main/install.sh)"

と叩いてみてください。指定した場所にリポジトリがクローンされ、シンボリックリンクが、~/.vimrc に作成されるはずです。 (デフォルトブランチ名がmainではなく、masterである場合は、mainmaster に変更してください)

ホームディレクトリ下で

ls -la

などで確認できます。僕の場合は、

.vimrc -> /home/fkubota/Git/dotfiles/vim/.vimrc

と出力されていました。

以上が簡単な紹介です。これを基本として追加したい項目を増やしていくだけです。 僕の場合は、 vim, tmux, fish のdotfilesを管理する以外にも必要なものを追加しています。
後はお好みで楽しんでください。
dotfiles、育てるとかわいくなっていきますよ。

おわりに

今回の記事で弊社のテックブログとしては、3本目。
今後も続々と楽しい記事をあげていく予定です。
カンムに少しでも興味ある方はぜひこちらから応募してください!!!

採用 | 株式会社カンム

PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を使う

カンムでバンドルカードのバックエンドやインフラを担当している summerwind です。

バンドルカードはスマホ上で Visa のプリペイドカードを発行して決済に使える機能を提供しているため、クレジットカードのデータを安全に取扱うことを目的として策定された、クレジットカード業界のセキュリティ基準である PCI DSS に準拠しています。

PCI DSS にはセキュリティ基準として様々な要件が定義されており、中には次のようなものがあります。

11.3.4.1 Additional requirement for service providers only: If segmentation is used, confirm PCI DSS scope by performing penetration testing on segmentation controls at least every six months and after any changes to segmentation controls/methods.

これは、ネットワークセグメンテーションを使用してカードデータを扱う環境を分離している場合は、少なくとも6ヶ月ごとにそのセグメンテーション制御に対するテストを行ない、意図した状態になっているかをテストすることが求めています。実際には、カードデータを扱わないシステムとカードデータを扱うシステムの間の通信が必要なプロトコルやポートに制限されていることをテストします。

これまでカンムでは Nmap などのツールを利用してこのネットワークセグメンテーションのテストを行なってきましたが、以下のような課題がありました。

  • テストの実行手順が明確に定義されていない
  • Nmap などのツールの実行には時間がかかる

もうちょっと簡単に素早くテストできないかと考えて見つけたのが、2020年末にリリースされた VPC Reachability Analyzer です。これは AWS VPC 内の2つのエンドポイント間で通信の到達性を検証してくれる機能で、まさにセグメンテーションテストの要件にぴったりです。

VPC Reachability Analyzer の実行は AWS コンソールから簡単に行えます。VPC Reachability Analyzer のページにアクセスしたら、Create and analyze path ボタンを押して、Path を作成します。Path はテストしたい2つのエンドポイント間の経路を示すものになるので、送信元と送信先および通信に使用するプロトコルを指定します。

f:id:kanmu-tech:20210511131831p:plain
Create and analyze path

Path を作成すると初回の検証が自動実行され、これが完了すると、到達性について結果が表示されます。Not reachable であれば到達不可であることが確認できたこととなり、セグメンテーションが有効であることが分かります。

f:id:kanmu-tech:20210511131909p:plain
Path

後日同じ経路で改めて検証を実行したい場合は、作成した Path の画面にある Analyze path ボタンを押すだけですぐに検証ができるので便利です。PCI DSS の要件 11.3.4 では開発者以外の第三者的な立場でこのテストを実行することを求めているので、そういった観点でも VPC Reachability Analyzer を活用するのがよいのではないかと考えています。

今回は PCI DSS のセグメンテーションテストに VPC Reachability Analyzer を活用する方法を紹介しました。今後も PCI DSS の要件を達成する方法などを紹介できればと思っています。

カンムではセキュアでモダンなクレジットカード決済インフラを作りたいエンジニアを積極的に採用しています!

GoCon CTF と呼ばれた問題の紹介と解説

こんにちは、バンドルカードを作っている Kanmu という会社で CTO をしています。kneeです。

昨日行われた Go Conference 2021 Spring にて Kanmu としてスポンサーをさせていただいており、そのオフィスアワーにて「CTF なんて言葉聞いたこともない、strings コマンドなんて知らない、でも Go は触ったことあるよ」という方に向けて Go を少し絡めたゆるい CTF の rev っぽい問題を出題させていただきました。
それなりにたくさんの方に楽しんでいただけたようですので、解説と合わせて出題者の意図の紹介をします。
ちなみに自分は CTF 超絶にわかですのでその点はご容赦ください。

まだ解いてないけど、解いてみたいという方はぜひ読み進める前に解いてみてください。
所要時間は解いていた方の様子を見るに5分~3時間程度です。

問題の紹介

問題はこれです https://github.com/kanmu/gocon2021_office_hour
ヒントや解説は時間経過に応じて追加していったものですので、出題当時は以下のような感じでした。

以下のイメージの中にGoのプログラムをビルドした実行ファイルがおいてあります。 これを調べて秘密の答えを見つけてください!

docker run -it ghcr.io/kanmu/gocon2021-office-hour:latest /bin/bash

実際に中を見てみるとこんな感じ。
問題文にある実行ファイルと MEMO がおいてあるだけ。そして実行してみるといきなり答えを聞いてくる、そんな感じの問題です。

$ docker run -it ghcr.io/kanmu/gocon2021-office-hour:latest /bin/bash
root@7a909bfa6f26:/go/src/app# ls
MEMO  gocon2021_office_hour
root@7a909bfa6f26:/go/src/app# ./gocon2021_office_hour
Enter your answer 答えを入力してください: 

想定解答と出題意図

想定解答の解説をしつつ出題意図を説明していきます。

まずノーヒントなので MEMO を見ます。 ちなみにこのイメージにはデフォルトで file コマンドすらなく、この時点でなんだこれとなられた方も多かったようです。

$ cat MEMO
何回失敗しても諦めないで!
Don't give up no matter how many times you fail!

煽ってきていますね。
しかし実際に諦めないで何度も試してみるとヒントが出るようになっています。

$ ./gocon2021_office_hour
Enter your answer 答えを入力してください: a
Failed 残念
Enter your answer 答えを入力してください: b
Failed 残念
Enter your answer 答えを入力してください: c
Failed 残念
Enter your answer 答えを入力してください: d
Failed 残念
Enter your answer 答えを入力してください: e
Failed 残念
Enter your answer 答えを入力してください: f
Failed 残念

You can user one of go tool command. Let's run `go tool`.
go tool ~~~ コマンドで使えるものがあるかも…? `go tool` を実行してみてください

You can usertypo です。

gocon2021_office_hour 自体を直接調べるという選択肢を持っていない場合、できることとしてぱっと思いつくのは、実行していろいろ入力してみる、他のファイルを探しに行くことぐらいだろうと想定していました。ただ後者は脱線して時間がかかりますし、前者はただの当てずっぽうになってしまう。
そういった状況で自然に gocon2021_office_hour 自体の解析に誘導する必要があり、何回も実行するだけならどんな前提知識の方もいけるだろうということでこういう形をとりました。 ただノーヒントでわからんとなって1,2回入力して離脱したら悲しいので諦めないでという MEMO を置くことにしました。

$ go tool
addr2line
asm
buildid
cgo
compile
cover
dist
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vet

ちょっと Go 要素が出てきました。ここが一番の難所です。go tool を使えとだけヒントが出ているので、どれが使えるのか自分で調べる必要があります。ほとんどの方は普段使ったことないコマンドもたくさんあると思うので調べたり試行錯誤することになります。 この過程で普段触れることのない Go に関する情報にあたってもらえたらいいなーというような気持ちがこもっています。

ちなみに正解は go tool nm で、これはシンボルを列挙するコマンドです。が、その意味を理解しておらずとも問題はありません。
また go tool foo gocon2021_office_hour と件の実行ファイルを引数に渡して人間に可読っぽい出力がされるのはおそらく nm ぐらいかと思います。というところでなんとか答えににじり寄っていってくれたらうれしいなという感じですかね。

$ go tool nm gocon2021_office_hour
  4df6f8 r $f64.3eb0000000000000
  4df700 r $f64.3f847ae147ae147b
  ...
  54efa0 D unicode.foldLu
  54efa8 D unicode.foldM
  54efb0 D unicode.foldMn
  46dd40 T unicode.init
  46d500 T unicode/utf8.DecodeRune
  46d700 T unicode/utf8.DecodeRuneInString
  46d900 T unicode/utf8.EncodeRune
  46da80 T unicode/utf8.RuneCount
  46dbe0 T unicode/utf8.RuneCountInString
  53ff40 D unicode/utf8.acceptRanges
  5430e0 D unicode/utf8.first

とはいえその出力は2000行以上になるので、その中から必要な情報を見つける必要があります。ちなみに見つけてほしい行はこれです。

  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

ここで想定していたのは2種類の行動で、1つ目は長すぎて読めないのでとりあえず関係ありそうな単語で grep してみること。

$ go tool nm gocon2021_office_hour | grep gocon
  540560 D github.com/kanmu/gocon_2021_kanmu..inittask
  49bb60 T github.com/kanmu/gocon_2021_kanmu.New
  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

もう一つはどうすればいいかわからないけど、とりあえず実行結果を下からスクロールして眺めていったら不自然に長い行に気づく、です。出力順序は go tool nm の実装的にオプションを渡さない限りは変わらないのでスクロールしていくと割とすぐ出てくるはずです。

  466aa0 T type..eq.[6]string
  466b60 T type..eq.[9]string
  49b0e0 T type..eq.fmt.fmt
  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
  401c20 T type..eq.internal/cpu.CacheLinePad
  401c40 T type..eq.internal/cpu.option

この go tool nm を実行して、grep するなどしてこの行をみつけるところは難所だろうと思っていたので、出題してしばらく経過した後にヒントを公開しました。

続きます。 見つかった行は以下です。

  49bc60 T type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

Let's Run This Command とあり、これが続きます strings_gocon2021_office_hour_grep_question

この _ で繋がれた文字列をみて strings コマンドを知っているかどうかで動きが変わります。知っていたらたぶんこのように分解するのは自明そうです。

strings gocon2021_office_hour | grep question

とはいえ知っていたらここにたどり着く前にゴールしてそうな気もしますし、そもそも想定解答者として strings コマンドも知らない人を置いている。かつ、そういった人にもこういうときに使う基本的なコマンドを一つでも覚えて帰ってもらいたいと思っていました。

ここで辿ってくれたらいいなーと思っていた思考の過程は以下です。 grep を知ってるのは前提で、途中で grep があるのでなにかを grep してるんじゃないかと想像し | grep question をひねり出す。つづいて strings_gocon2021_office_hour という部分の分解においては、 gocon2021_office_hour が実行ファイル名、また出題のリポジトリ名であることで一つの単語であることを想起し、余った strings という謎の存在を最後もしかしてこういうコマンドがあるのでは!?とひらめいてググってみるなどして答えにたどり着く。 という感じでした。

ここもやはり strings コマンド知らないとなかなか難しかったようですが、実際にそのような方が最終的に strings コマンドに辿り着いておられるのを拝見して、めちゃくちゃテンションがあがりました。

そしてここまで来たらもうゴールは目の前です。見つけたコマンドを実行します。

$ strings gocon2021_office_hour | grep question
P*gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
  *************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************  000102030405060708091011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798990w
type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question
github.com/kanmu/gocon_2021_kanmu.(*LetsRunThisCommand_strings_gocon2021_office_hour_grep_question).Run
type..eq.github.com/kanmu/gocon_2021_kanmu.LetsRunThisCommand_strings_gocon2021_office_hour_grep_question

明らかに怪しい部分があるので取り出してみると、問題がかいてあります。

*************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************

クレジットカードのメッセージングの国際標準が答えです。意味がわからなくても問題文をそのまま検索したらヒットします。

ということで答えは ISO8583 です。

ソースコード

使った Go のソースコードが気になるところだと思うので公開します。
直前に慌てて作問していてなぜかソースコードrm するという失態をおかしたのでそのままのソースコードは残っておらず思い出しながら書きました。おおまかな作りはあってるとおもいます。 真に知りたい方はデバッガで見るなどして補完ください。

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "os"
  
  "github.com/kanmu/gocon_2021_kanmu"
)

func m5(text string) string {
    hasher := md5.New()
    hasher.Write([]byte(text))
    return hex.EncodeToString(hasher.Sum(nil))
}

func main() {
    x := "*************  question: what is the international standard of credit card messaging? The answer is ISOxxxx  ***************"
    fmt.Fprintf(ioutil.Discard, x)
    y := gocon_2021_kanmu.New().Run()
    fmt.Fprintf(ioutil.Discard, y)

    answer := "bc9ad0a243f1c91268437fefb3beba6b"
    i := 0
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        if m5(scanner.Text()) == answer {
            fmt.Println("Success! 正解です!すごい、おめでとうございます!")
        } else {
            fmt.Println("Failed 残念")
            if i == 5 {
                fmt.Println("You can user one of go tool command. Let's run `go tool`.")
                fmt.Println("go tool ~~~ コマンドで使えるものがあるかも…? `go tool` を実行してみてください")
            }
            i += 1
        }
    }
    if err := scanner.Err(); err != nil {
        os.Exit(1)
    }
}
package gocon_2021_kanmu

import (
    "math/rand"
    "time"
)

type LetsRunThisCommand_strings_gocon2021_office_hour_grep_question struct {
    x string
    y int
}

func (h *LetsRunThisCommand_strings_gocon2021_office_hour_grep_question) Run() string {
    return h.x
}

func New() *LetsRunThisCommand_strings_gocon2021_office_hour_grep_question {
    rand.Seed(time.Now().UnixNano())
    y := rand.Int() + 1
    return &LetsRunThisCommand_strings_gocon2021_office_hour_grep_question{
        x: "x",
        y: y,
    }
}

おわりに

Twitter での反響を見るに想定していたよりとても多くの方に楽しんでいただけたようで大変うれしかったです。
次回機会があれば strings だけでは倒せない歯ごたえがある問題も用意しようと思うので、今回興味を持ってもらえた方はぜひ CTF に入門して倒せるように鍛えてきてください!

この記事は Kanmu のテックブログの一発目なのですが、まさかの CTF の解説になってしまいました。
今後 Kanmu での普段のプロダクト開発の様子もいろいろ紹介できればと思っているのでのでぜひお楽しみに!
採用 | 株式会社カンム

GoCon の運営の皆様も参加してくださった方々も本当に楽しい会をありがとうございました!
ではまた。