ECSとDatadogを使ったネットワーク機器のモニタリング

インフラエンジニアの菅原です。

カンムはバンドルカードというVisaプリペイドカードのサービスを提供していますが、Visaと決済情報をやりとりするためにオンプレミスのサーバと通信しています。

カンムのサービスはAWS上で構築されており、AWSとオンプレミスのサーバの通信はAWS Direct Connectを経由してます。

また、ネットワーク制御のためスイッチとしてCisco CatalystとJuniper SRXを使用しています。

f:id:winebarrel:20220130132559j:plain

ネットワーク機器は通常のサーバと同様になにかしらの問題が発生することがあるため、SNMPによるメトリクスの収集やSNMPトラップでのイベントの検知が必要になります。

また、Syslogはネットワーク機器内にファイルとして保存されていますが、外部にログを転送・保存しておくことで何か問題が発生したときに分析がやりやすくなります。

以前まではEC2インスタンスSNMPの収集・SNMPトラップの受信・ネットワーク機器用のSyslogサーバ、NTPサーバの運用を行っていました。

f:id:winebarrel:20220130134323j:plain

ECSとDatadogによる監視の構築

EC2インスタンスはサーバーの自体の管理やOS・ミドルウェアのアップデートなどでそれなりに運用の手間がかかります。

そこでECSとDatadogを使って、コンテナとSaaSでネットワーク機器の監視をできるようにしました。

f:id:winebarrel:20220130135659j:plain

Datadog AgentによるSNMPの収集とSNMPトラップの受信

ネットワーク機器のSNMPの収集とSNMPトラップの受信にはDatadog Agentのコンテナを使用しています。*1

SNMPトラップはUDPで送信されるためNetwork Load Balancer(NLB)を使ったECSサービスを作成しました。

Dockerfile

FROM datadog/agent:7

# (中略)

COPY datadog.yaml.tmpl /etc/datadog-agent/
COPY snmp.d_conf.yaml.tmpl /etc/datadog-agent/conf.d/snmp.d/conf.yaml.tmpl
COPY ping.d_conf.yaml.tmpl /etc/datadog-agent/conf.d/ping.d/conf.yaml.tmpl

# https://github.com/progrium/entrykit を使っています
ENTRYPOINT [ \
  "render",\
  "/etc/datadog-agent/datadog.yaml", \
  "--", \
  "render",\
  "/etc/datadog-agent/conf.d/snmp.d/conf.yaml", \
  "--", \
  "/bin/entrypoint.sh" \
  ]

datadog.yml

# cf. https://github.com/DataDog/datadog-agent/blob/main/pkg/config/config_template.yaml
snmp_traps_enabled: true
snmp_traps_config:
  bind_host: "0.0.0.0"
  community_strings:
    - '{{ var "COMMUNITY_STRING" }}'

# NOTE: Needed for SNMP trap
logs_enabled: true

snmp.d/conf.yml

# cf. https://docs.datadoghq.com/ja/network_performance_monitoring/devices/setup/?tab=snmpv2
init_config:
  loader: core
  use_device_id_as_hostname: true
instances:
{{ range $_, $ip_address := var "IP_ADDRESSES" | split "," }}
- ip_address: "{{ $ip_address }}"
  community_string: "{{ var "COMMUNITY_STRING" }}"
{{ end }}

Datadog Agentで収集された情報はDatadogに送られます。

f:id:winebarrel:20220130141331p:plain

SNMPトラップはDatadog Logsに送られます。

f:id:winebarrel:20220130141837p:plain

RsyslogによるSyslogの受信とDatadogへの送信

ネットワーク機器からのSyslogの受信にはRsyslogのコンテナを使用しています。

Datadog Agentと同じNLBを使ったECSサービス上でコンテナを起動し、受信したSyslogはDadadog Logsへと送られます。*2

Dockefile

FROM    ubuntu:20.04

# (中略)

COPY rsyslog.conf.tmpl /etc/
COPY datadog.conf.tmpl /etc/rsyslog.d/

ENTRYPOINT [ \
  "render",\
  "/etc/rsyslog.d/datadog.conf", \
  "--", \
  "render",\
  "/etc/rsyslog.conf", \
  "--", \
  "rsyslogd", "-n" \
  ]

rsyslog.conf

module(load="imuxsock")
module(load="immark" interval="20")

module(load="imudp")
input(type="imudp" port="{{ var "RSYSLOG_PORT" | default 514 }}")

module(load="imtcp")
input(type="imtcp" port="514")

module(load="omstdout")

$WorkDirectory /var/spool/rsyslog
$IncludeConfig /etc/rsyslog.d/*.conf
$AbortOnUncleanConfig on
$DefaultNetstreamDriverCAFile /etc/ssl/certs/ca-certificates.crt

action(type="omstdout")

datadog.conf

## Set the Datadog Format to send the logs
$template DatadogFormat,"{{ var "DD_API_KEY" }} <%pri%>%protocol-version% %timestamp:::date-rfc3339% %HOSTNAME% %app-name% - - [metas ddsource=\"rsyslog\" ddtags=\"env:prd\"] %msg%\n"

action(
  type="omfwd"
  protocol="tcp"
  target="intake.logs.datadoghq.com"
  port="10516" template="DatadogFormat"
  StreamDriver="gtls"
  StreamDriverMode="1"
  StreamDriverAuthMode="x509/name"
  StreamDriverPermittedPeers="*.logs.datadoghq.com"
  action.resumeRetryCount="10"
  action.reportSuspension="on"
)

Datadog Logsに送られたSyslogはコンソールから見ることができます。

f:id:winebarrel:20220130143356p:plain

Amazon Time Sync ServiceによるNTPサービス

ネットワーク機器はNTPサーバとしてAWS上のサーバを参照しています。

ntpdのコンテナを作成してもよかったのですがAWSAmazon Time Sync Serviceを提供しているので、stoneを使ってNTPをAmazon Time Sync Serviceに中継するようにしました。

Dockerfile

FROM debian:bullseye AS build

ARG STONE_VERSION=2.4

RUN apt-get update && \
  apt-get install -y curl build-essential

RUN curl -sSfLO https://www.gcd.org/sengoku/stone/stone-${STONE_VERSION}.tar.gz && \
  tar xf stone-${STONE_VERSION}.tar.gz --strip-components 1 && \
  make linux

FROM debian:bullseye-slim

COPY --from=build stone /usr/local/bin/

ENTRYPOINT ["/usr/local/bin/stone"]

タスク定義の一部

      command: [
        // NTP
        // cf. https://aws.amazon.com/jp/blogs/news/keeping-time-with-amazon-time-sync-service/
        '169.254.169.123:123/udp',
        '123/udp',
        '--',
        // HTTP (for healthcheck)
        '169.254.169.253:53',
        '80',
      ],

苦労した点

NLBのヘルスチェック

NLBでUDPを使っている場合でもヘルスチェックはTCPで行われます。 そのため、各コンテナでTCPのヘルスチェックができるように工夫しました。

  • Datadog Agentはいくつかデーモンが立ち上がっているので、そのうちの一つでLISTENされているポートをヘルスチェックに利用しています
  • RsyslogはTCPでのSyslogの受信は行わないのですが、ヘルスチェックのためにinput(type="imtcp" port="514")の設定を追加しました
  • stoneはそれ自体がヘルスチェック機能を持っていないので、VPCDNSサーバにTCPパケットを中継してヘルスチェックとしています

DatadogとRsyslogの接続が切れる

ドキュメントにも書いてあるのですが、DatadogとRsyslogの接続は非アクティブな状態が続くと切断されて再接続ができません。

このためmodule(load="immark" interval="20")して定期的にログを流すようにしています。 また、切断されても気づけるようにログが一定時間流れなかったらアラートをあげるようにもしています。

ECSのデプロイ後にSyslogが受信できなくなる

ECSをデプロイすると一部のネットワーク機器からSyslogが受信できなくなるという問題もありました。 ネットワーク機器はNLBのIPアドレスを参照しているのですが、デプロイ完了後も古いコンテナのほうにSyslogが流れて続けてしまい、新しいコンテナにはSyslogが流れなくなるという状態になっていました。

詳しい原因を調査できていないのですが、NLBのTarget GroupでConnection termination on deregistrationを有効にすることで、この問題を解決できました。

f:id:winebarrel:20220130150057p:plain

まとめ

いままでは監視用のEC2インスタンスの運用が地味に手間だったのですが、コンテナ化によってだいぶ手間を軽減することができました。

また、Datadogを利用することでメトリクスやログの閲覧がとても楽になりました。

カンムでは引き続きEC2からECSの移行が進行中です。興味のあるインフラエンジニアを絶賛募集しております。

open.talentio.com

ECSで作業用のタスクをサクッと作るためのツールを作成した

インフラエンジニアの菅原です。

最近、バイクに念願のグリップヒーターをつけました。 これでツーリング時の手の寒さが多少楽になりそうで喜んでいます。

とはいってもなかなか出かけられないのですが…


現在私はAWS Fargateを使ったサービスをECS上に構築を進めており、日々コンテナと戯れています。

基本的にストレージ以外のコンポーネントはほとんどECSで動いているのですが、VPCのネットワーク内でちょっとした作業(たとえばネットワークの疎通確認など)をしたい場合、都度新しいタスクを起動して作業しています。 また、DBにテストデータを入れたかったり、どうしてもDBを直接操作したいことがある場合、stoneを新しいタスクを起動した上で、そのタスクを踏み台としてaws ssm start-sessionでポートフォワーディングを行い、手元から直接DBにアクセスできるようにしたりしています。

しかしそのような一時的なタスクの起動は

  1. タスク定義のディレクトリに移動する*1
  2. タスクを起動
  3. 起動したコンテナにECS Execでログイン、あるいはポートフォワーディングをする場合はaws ssm start-sessionを実行
  4. 作業後はタスクを停止

…と、なかなか手間がかかります。

imageを実行時にオーバーライドできないので、都度都度タスク定義をエディタで書き換えるのも面倒です。

アプリケーションを動かしているコンテナにECS Execでログインすることもできるのですが、稼働しているコンテナにログインしたくはないですし、そのコンテナにパッケージをインストールするのもさすがに憚られます。

かといって作業用・ポートフォワーディング用にEC2インスタンスを動かすのは、管理コストなどからやりたくはないです。

もっと簡単に作業したい、kubectl run/exec/port-forwardのようにサクッと作業用のコンテナを作りたい…

と考えてそれらをなんとかするツール、demitasを作成しました。

demitas

github.com

demitasはecspressoのラッパーで、ECSタスクの起動・ECS Exec・ポートフォワーディングを簡単にするツールです。

  • タスク定義を~/.demitas配下で一括管理する
  • 単一のコンテナの定義だけ書ける
  • すべての定義を実行時にオーバーライドできる

などの特徴があります。

使い方

まず~/.demitas配下に設定ファイルを作成します。

~/.demitas
├── ecs-container-def.jsonnet
├── ecs-service-def.jsonnet
├── ecs-task-def.jsonnet
└── ecspresso.yml

基本的にecspressoの設定と同じですがecs-task-def.jsonnetにcontainerDefinitionsがないです。 そのかわりecs-container-def.jsonnetに単一のコンテナの定義を書いています。

// ecs-service-def.jsonnet
{
  name: 'oneshot',
  cpu: 0,
  image: 'ubuntu',
  essential: true,
  logConfiguration: {
    logDriver: 'awslogs',
    options: {
      'awslogs-group': '/ecs/oneshot',
      'awslogs-region': 'ap-northeast-1',
      'awslogs-stream-prefix': 'ecs',
    },
  },
}

設定ファイルを作成したら、どのディレクトリにいてもdemitasコマンドでタスクを起動できます。

$ demitas -c '{image: "public.ecr.aws/runecast/busybox:1.33.1", command: [echo, test]}'
2021/10/30 16:52:45 hello/hello Running task
2021/10/30 16:52:45 hello/hello Registering a new task definition...
2021/10/30 16:52:46 hello/hello Task definition is registered busybox:46
2021/10/30 16:52:46 hello/hello Running task
2021/10/30 16:52:47 hello/hello Task ARN: arn:aws:ecs:ap-northeast-1:822997939312:task/hello/d51ca2de190548e2a2b8e8c9644cfab1
2021/10/30 16:52:47 hello/hello Waiting for run task...(it may take a while)
2021/10/30 16:52:47 hello/hello Watching container: busybox
2021/10/30 16:52:47 hello/hello logGroup: /ecs/busybox
2021/10/30 16:52:47 hello/hello logStream: ecs/busybox/d51ca2de190548e2a2b8e8c9644cfab1
..

すべての定義はdemitasのオプションでオーバーライド可能です。上記の例ではコンテナのイメージとコマンドをオーバーライドしています。

また、設定ファイルのディレクトリをさらに~/.demitas/db-subnet ~/.demitas/app-subnetなどと分けることで、実行時にプロファイルを指定してタスクを起動できます。

~% demitas -p db-subnet -c '{command: [psql, -c, "SELECT * FROM foo"]}'

demitas-exec・demitas-pf

demitasではさらに起動したコンテナにログインしたり、ポートフォワーディングを簡易化するためのラッパーを作成しました。

demitas-execはタスクの起動・ECS Exec・タスクの停止を行います。

$ demitas-exec -e bash
Start ECS task...
ECS task is running: 8fba2576ba3841e7aff88f4ecfb7b32b

The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-05d903fcaef0393ed
root@ip-10-0-0-18:/# echo test
test
root@ip-10-0-0-18:/# exit
exit


Exiting session with sessionId: ecs-execute-command-05d903fcaef0393ed.

Stopping ECS task... (Please wait for a while): 8fba2576ba3841e7aff88f4ecfb7b32b
done

demitas-pfはタスクの起動・ポートフォワーディング・タスクの停止を行います。

$ demitas-pf -h www.yahoo.com -r 80 -l 10080
Start ECS task for port forwarding...
ECS task is running: c16548617cab480e8fb37f195a8be708
Start port forwarding...

Starting session with SessionId: root-084c5c16763c0f36f
Port 10080 opened for sessionId root-084c5c16763c0f36f.
Waiting for connections...

Connection accepted for session [root-084c5c16763c0f36f]
^CTerminate signal received, exiting.


Exiting session with sessionId: root-084c5c16763c0f36f.

Stopping ECS task... (Please wait for a while): c16548617cab480e8fb37f195a8be708
done
$ curl -s localhost:10080 | grep title
    <title>Yahoo</title>

まとめ

kubectl run、欲しいなぁ、欲しいなぁ」とずーっと思っていたのですが、demitasでだいぶ解消されました。 いまはdocker runぐらいの感覚で作業用タスクの起動しています。

*1:ecspressoを使っています

Go Conference 2021 Autumn CTF: Go 1.16.4 に含まれる脆弱性を突いてリバースプロキシを突破する

エンジニアの佐野です。Go Conference 2021 Autumn にて Kanmu はスポンサー枠をいただき、オフィスアワーの催しで Go x セキュリティというコンセプトの CTF のような問題を用意させていただきました。

問題はこちら "Go" beyond your proxy になります。

github.com

f:id:kanmu-tech:20211112223834p:plain The Go gopher was designed by Renee French.

当日解けなかった人やこのブログを読んで興味が沸いた人もチャレンジしてみてください。

問題を簡単に説明すると、 Go 1.16.4 で書かれたリバースプロキシの背後の HTTP サーバに flag.txt というファイルが置かれています。このファイルには簡単なアクセス制限が施されているのですが、それを突破してそのファイルの中身を参照して解答してください、というものになります。 Go 1.16.4 には CVE-2021-33197脆弱性が含まれていて Go の issue にも上がっています(次のバージョンである 1.16.5 で Fix されています)。この脆弱性を利用してアクセス制限を突破するというのが想定解法になります。

※ 蛇足になりますがこのようにアプリケーションレイヤーにて送信元IPでアクセスコントロールすることはおすすめしません

本記事では出題の意図、問題の解説と解き方、問題を作るときに考えていたことを書きます。

  • 出題の意図
  • 問題の解説と想定解法
  • 問題を作るときに考えていたこと
  • 小ネタ
  • おわりに

1. 出題の意図

出題の意図としては Go に潜むセキュリティ issue を知ってもらい、実際にその脆弱性を突いたハックを体験してもらうことになります。

この問題を通して、

  • Go 本体にセキュリティ issue が潜んでいることを知る
  • Go の標準ライブラリを読む

という経験を積んでもらえていたら幸いです。

1.1 Go 本体に潜むセキュリティ issue

Go 本体にもセキュリティ関連の issue は報告されていて随時その修正がされています。試しに Go のコミットログから "CVE" という文字列を検索してみます。

git log -i --grep 'cve' --oneline
61536ec030 debug/macho: fail on invalid dynamic symbol table command
77f2750f43 misc/wasm, cmd/link: do not let command line args overwrite global data
5abfd2379b [dev.fuzz] all: merge master (65f0d24) into dev.fuzz
bacbc33439 archive/zip: prevent preallocation check from overflowing
b7a85e0003 net/http/httputil: close incoming ReverseProxy request body
a98589711d crypto/tls: test key type when casting
aa4da4f189 [dev.cmdgo] all: merge master (912f075) into dev.cmdgo
ad7e5b219e [dev.typeparams] all: merge master (4711bf3) into dev.typeparams
f9d50953b9 net: fix failure of TestCVE202133195
0e39cdc0e9 [dev.typeparams] all: merge master (8212707) into dev.typeparams
106851ad73 [dev.fuzz] all: merge master (dd7ba3b) into dev.fuzz
dd7ba3ba2c net: don't rely on system hosts in TestCVE202133195
cdcd02842d net: verify results from Lookup* are valid domain names
950fa11c4c net/http/httputil: always remove hop-by-hop headers
74242baa41 archive/zip: only preallocate File slice if reasonably sized
c89f1224a5 net: verify results from Lookup* are valid domain names
a9cfd55e2b encoding/xml: replace comments inside directives with a space
4d014e7231 encoding/xml: handle leading, trailing, or double colons in names
d0b79e3513 encoding/xml: prevent infinite loop while decoding
cd3b4ca9f2 archive/zip: fix panic in Reader.Open
953d1feca9 all: introduce and use internal/execabs
46e2e2e9d9 cmd/go: pass resolved CC, GCCGO to cgo
d95ca91380 crypto/elliptic: fix P-224 field reduction
dea6d94a44 math/big: add test for recursive division panic
062e0e5ce6 cmd/go, cmd/cgo: don't let bogus symbol set cgo_ldflag
1e1fa5903b math/big: fix shift for recursive division
64fb6ae95f runtime: stop preemption during syscall.Exec on Darwin
4f5cd0c033 net/http/cgi,net/http/fcgi: add Content-Type detection
027d7241ce encoding/binary: read at most MaxVarintLen64 bytes in ReadUvarint
fa98f46741 net/http: synchronize "100 Continue" write and Handler writes
82175e699a crypto/x509: respect VerifyOptions.KeyUsages on Windows
b13ce14c4a src/go.mod: import x/crypto/cryptobyte security fix for 32-bit archs
953bc8f391 crypto/x509: mitigate CVE-2020-0601 verification bypass on Windows
552987fdbf crypto/dsa: prevent bad public keys from causing panic
41b1f88efa net/textproto: don't normalize headers with spaces before the colon
145e193131 net/http: update bundled golang.org/x/net/http2 to import security fix
61bb56ad63 net/url: make Hostname and Port predictable for invalid Host values
12279faa72 os: pass correct environment when creating Windows processes
9b6e9f0c8c runtime: safely load DLLs
193c16a364 crypto/elliptic: reduce subtraction term to prevent long busy loop
1102616c77 cmd/go: fix command injection in VCS path
1dcb5836ad cmd/go: accept only limited compiler and linker flags in #cgo directives
2d1bd1fe9d syscall: fix Exec on solaris
91139b87f7 runtime, syscall: workaround for bug in Linux's execve
8d1d9292ff syscall: document that Exec wraps execve(2)
cad4e97af8 [release-branch.go1.7] net/http, net/http/cgi: fix for CGI + HTTP_PROXY security issue
b97df54c31 net/http, net/http/cgi: fix for CGI + HTTP_PROXY security issue
84cfba17c2 runtime: don't always unblock all signals
eeb8d00c86 syscall: work around FreeBSD execve kernel bug

本問題の修正コミットである 950fa11c4c net/http/httputil: always remove hop-by-hop headers に加えて他の修正も多くヒットします。

ちなみにちょうど先日 Go 1.17.3, 1.16.10 がリリースされましたがこれらにもセキュリティ Fix が含まれていました。

セキュリティ関連のバグというと言語そのものよりもその言語を利用して実装されたウェブサーバやデータベースなどのミドルウェア、OS、その他ソフトウェアなどに注目しがちですが、言語自体にもセキュリティの問題は潜んでいることがあります。

私が書いた問題のコード自体にもバグはなかった(はず)です。しかしバグは Go の標準ライブラリの方に含まれている、というのがこの問題を解くポイントです。

1.2 Go の標準ライブラリを読む

issue とその修正 PR を見てみます。本問題の肝となっている issue とそれに対応する PR が下記なのですが、これらが問題を解くための最大のヒントになります。

github.com

github.com

詳しい解説は次の「問題の解説と想定解法」でしますが、この issue と修正コミットおよびそのテストコードから、

  • そもそも Connection ヘッダの仕様として、任意のヘッダ名を値に入れるとそのヘッダを消すことができる
  • 同じく Connection ヘッダの仕様として、Connection ヘッダは Proxy を経由する際にはそれ自体が削除される
  • しかし Go 1.16.4 では空の Connection ヘッダをリバースプロキシに送りつけるとそのまま背後のサーバに到達させることができる
  • Abusing HTTP hop-by-hop request headers という攻撃手法がある
  • 脆弱性を利用すると X-Forwarded-For を消すことができそうだ

といったことを読み取ることができます。本問題を解くためには Go の net/http/httputil パッケージとそのテストコードを少し読む必要があります。

2. 問題の解説と想定解法

私が想定した解答へのルートは次の流れの通りです。

  • サーバにリクエストを投げつつ問題のソースを読んでみる
  • Go のバージョンを特定する(気づく)
  • Go のバージョンに潜む脆弱性を確認して issue にたどり着く
  • issue の修正 PR や issue に貼られた Abusing hop by hop header を調べる
  • 空の Connection ヘッダとともに Connection: X-Forwarded-For を送りつける

「3. 問題を作るときに考えていたこと」で書きますが、挑戦者にいかにバージョンに目を付けてもらいどのように issue に誘導するか?というのが作問中の悩みでした。ヒントでいきなり issue を教えると簡単すぎる、しかし issue にたどり着けないと明後日の方向のアプローチをしてしまう。最初のヒントで Go 1.16.4 を強調したのはこのためです。

2.1 サーバにリクエストを投げつつ問題のソースを読んでみる

docker run でサーバを起動したら単純に 8000 番ポートにリクエストを投げてみます。以下のようなトレースが出力されます。

========================================================
Welcome to Kanmu Office hour @ Go Conference 2021 Autumn
"Go" beyond your proxy! Go version: go1.16.4
---------------- Front Proxy ----------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1

--- Front Proxy が受信した RemoteAddr ---
RemoteAddr: 172.17.0.1:58588

---------------- Middle Proxy ----------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1
X-Forwarded-For: 172.17.0.1

--- Middle Proxy が受信した RemoteAddr ---
RemoteAddr: 127.0.0.1:38448

---------------- Backend Server ------------------
GET /flag.txt HTTP/1.1
Host: localhost:8000
Accept-Encoding: gzip
User-Agent: Go-http-client/1.1
X-Forwarded-For: 172.17.0.1, 127.0.0.1

--- Backend Server が受信した RemoteAddr ---
RemoteAddr: 127.0.0.1:51188

--- 最終的な X-Forwarded-For と送信元IP ---
X-Forwarded-For: 172.17.0.1, 127.0.0.1
Source IP: 172.17.0.1

残念!送信元IP が 127.0.0.1 になるようにリクエストを送ってください!(172.17.0.1 != 127.0.0.1)
==========================

トレースを見つつ、問題のソースを読んでみると backend に到達したときの Source IP が 127.0.0.1 であればフラグが取れるということがわかります。コードの解説と模式図はヒントに書いた通りです。

人によっては送信元IPを変更してリクエストを送信してみたり、X-Forwarded-For を送りつけてみたりしたかもしれませんが、問題のコード自体にはおそらくバグはないはずです。

2.2 Go のバージョンを特定する(気づく)

1.16.4 を使っていることに気づいてもらいます。docker run 実行時、ヒント、go.mod の中身などバージョンを知ることができる箇所はいくつかあります。

2.3 Go のバージョンに潜む脆弱性を確認して issue にたどり着く

こちらについては検索します。Go 1.16.4 について Google 検索, issue の探索, Goのリリースノートを調べるなどなんでも良いです。「検索かよ...」と思う人もいるかもしれませんが、使われているソフトウェアのバージョンを調べてそれに関する既知の問題を調べるのはオフェンシブセキュリティという文脈では正攻法の一つになります。

2.4 issue の修正 PR や issue に貼られた Abusing hop by hop header を調べる

Go 1.16.4 やリバースプロキシについて調べていると issue にたどり着くことができます。たどり着けずにヒントが出たことで辿れた人もいるかもしれません。たどり着いたら issue を読みます。

github.com

issue を見るとまず Connection ヘッダの説明が書かれています。プロキシによって Connection ヘッダは削除されること。また Connection ヘッダに値としてセットされているヘッダも同様に削除されること。そしてこの issue によると X-Forwarded-For のようなヘッダをドロップできるかもしれないと示唆するとともに、Abusing HTTP hop-by-hop request headers というタイトルの記事のリンクが貼られています。

そしてこの issue から辿れる PR にはこの issue の修正コミットとそのテストコードが追加されています。

github.com

テストコードを読んでみると frontend と backend 2つの HTTP サーバを起動しています。frontend は NewSingleHostReverseProxy を使ってバックエンドにリクエストを転送するような構成になっています。本問題では front, middle, backend の多段構成ですが、これと非常に似ています。

テストコードは何を確認しているでしょうか?テストするにあたり、空の値を持つ Connection ヘッダを送信していること、Connection ヘッダの値として X-Some-Conn-Header をセットして送信していることがわかります。そして Connection ヘッダとその値は backend では削除されることを確認しています。

そして当の標準ライブラリの修正はどうでしょうか?以下のあたりが消されていますね。

   for _, h := range hopHeaders {
        hv := outreq.Header.Get(h)
        if hv == "" {
            continue
        }
        if h == "Te" && hv == "trailers" {
            // Issue 21096: tell backend applications that
            // care about trailer support that we support
            // trailers. (We do, but we don't go out of
            // our way to advertise that unless the
            // incoming client request thought it was
            // worth mentioning)
            continue
        }
        outreq.Header.Del(h)
    }

これは hopHeaders (Connectionヘッダなど hop-by-hop header 一式が定義されている)の値を取得して削除するが、その値が空だったら削除しない、という処理をしています。つまり本来であれば Connection ヘッダは転送する際には削除するべきなのですが、空の値が含まれていたらそれは削除せずにそのまま転送するという処理になっていたようです。

2.5 空の Connection ヘッダとともに Connection: X-Forwarded-For を送りつける

ここまでで、

  • [仕様] Connection ヘッダはその値に含まれているヘッダを消す
  • [バグ] 普通は裏側には Connection ヘッダ自体を転送しないが、空の値を持たせると削除されずに転送してしまう

ということがわかりました。ということで以下のようなコードで空の Connection ヘッダと、 Connection: X-Forwarded-For を送ってみましょう。

package main

import (
        "bytes"
        "fmt"
        "io"
        "log"
        "net/http"
)

func main() {
        req, err := http.NewRequest("GET", "http://localhost:8000/flag.txt", nil)
        if err != nil {
                log.Fatal(err)
        }
        req.Header.Add("Connection", "")
        req.Header.Add("Connection", "X-Forwarded-For")

        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {
                log.Fatal(err)
        }
        defer resp.Body.Close()

        bb := &bytes.Buffer{}
        io.Copy(bb, resp.Body)
        fmt.Println(bb.String())
}

あっさりフラグが取れました。Connection ヘッダが裏側まで届き、Connection: X-Forwarded-For が設定されていることで X-Forwarded-For が削除されました。

フラグはこのURLですね。本記事の冒頭の Gopher くんと正解のメッセージが現れます。

https://gocon2021autumn-ctf-flag.net/

3. 問題を作るときに考えていたこと

ここから先は裏話になります。このような問題を考えることは初めてだったのでいろいろ考えをする必要がありました。その際に考えていたことを書いてみます。要約すると次のようなことを考えながら問題および当日のヒントを考えました。

  • CTF といっても Go を中心にした問題にすること
  • 前回よりも少し難易度を高めること
  • 最終的に全員が解ける問題にすること
  • いかに Go 1.16.4 の issue に誘導するか

3.1 CTFといっても Go を中心にした問題にすること

Go Conference ということもあり基本的には Go の問題であるべきです。しかしながらそこにセキュリティを絡めた CTF のような問題を作れるだろうか?と悩みました。

先ほど、ソフトウェアのバージョンから既知の脆弱性を調べるのはセキュリティの攻撃の世界では正攻法であると書きました。なんか良いバグないかな?と Go のコミットログを眺めていたら割と最近でしかも扱いやすいリバースプロキシの修正コミットがありました。

この問題を作ることができたのはちょうど良い issue があったということに尽きます。他にもいくつか問題を考えたのですが、どうしても Go というよりは Linux のテクニックの問題になってしまったりしてちょうどいい問題を作るのにいくらか難儀しました。

3.2 前回よりも少し難易度を高めること

カンムは前回の Go Conference 2021 Spring でも CTF 様式の問題を出題しております。以下が前回の問題の解説記事なのですが、

tech.kanmu.co.jp

次回機会があれば strings だけでは倒せない歯ごたえがある問題も用意しようと思うので、今回興味を持ってもらえた方はぜひ CTF に入門して倒せるように鍛えてきてください!

と書き残していました。ということで今回は少し骨のある問題を用意しようと思って問題を作成しました。 Go のソースは読める+HTTPの知識がある程度ある人というレベル感にしましたが、HTTP と題材であるリバースプロキシの知識については知らない人であっても挑戦しやすいようにヒントに説明を書きました。あの説明で伝わっていれば幸いです。

3.3 最終的に全員が解ける問題にすること

本丸は登壇者のトークなのでそれを邪魔しない程度の分量、難易度にすべきと考えました。「ほーら、解けねーだろ(笑)」という問題ではなく、こちらがヒントを出して解答に誘導しつつも最終的には全員が解ける問題になるように作問しました。 重要なのは本問題を通して Go のセキュリティに関心を持ってもらうことと、Go の標準ライブラリのコードや issue を読むという体験をしてもらうことです。

3.4 いかに Go 1.16.4 の issue に誘導するか

作問中、そして本番での運営では、挑戦者にいかにバージョンに目を付けてもらいどのように issue に誘導するか?に頭を悩ませました。プロトタイプを CTO に解いてもらってのですが、最初にもらったフィードバックは、

  • 脆弱性を調べるという発想がないと明後日の方向のアプローチをしてしまいそう
  • ふつうの人は脆弱性を自主的に探しにいかなそう -とりあえず Go のソース読むかということで自分は進めたけど、まず初心者の人にはそこでとまってしまいそう
  • そもそも HTTP ヘッダーの仕組みを理解してるか、知っていたとして細工した HTTP リクエスト投げれるか
  • Issue とか全部英語なのでそこにもハードルがありそう

などでした。

当日の運営では開始直後にいきなりヒントを出し、そこでバージョンと脆弱性の存在を匂わせる形にしました。そこからタイムラインなどの様子を見て次のヒントを考えて誘導していこう、と話をしていました。

4. 小ネタ

4.1 コミットID

3319700 になっているのですがこれは CVE-2021-33197 に合わせました。

f:id:kanmu-tech:20211113131822p:plain

こちらのツールを使うことでコミットIDを好きなものに変更できます。

github.com

4.2 正解のページの Gopher くんは何?

わたしの手書きです。わたしがハッカーっぽい Gopher くんを書いて CTO がそれに魂を吹き込んでくれて本記事の冒頭にも載っている闇の底から覗く Gopher くんができあがりました。

f:id:kanmu-tech:20211113132835p:plain The Go gopher was designed by Renee French.

5. おわりに

Twitter などを見ると今回も多くの方に解いていただけました。作問担当としては感無量です!ありがとうございます!

そしてお約束の宣伝をさせてください。カンムでは Go やセキュリティに関心のあるエンジニア、もちろんそれ以外の職種も募集しております! kanmu.co.jp

GoCon の運営の皆様、参加してくださった皆様ありがとうございました!

おわり

カンムは Go Conference 2021 Autumn にスポンサーとして参加します #GoConference #gocon

こんにちは!カンムで採用担当をやっている @ayapoyo と申します(テックブログ初参戦です!)

11月13日は Go Conference 2021 Autumn の開催日ですね! 今回もたくさんの gopher とお話できることを楽しみにしております。

gocon.jp

シルバースポンサーやります ʕ◔ϖ◔ʔ

4月に開催された Go Conference 2021 Spring に引き続き、今回もスポンサーとして Go Conference に参加させていただきます!

カンムが展開する "バンドルカード" そして新規事業の "Pool" のバックエンドは Go メインで開発しており、このイベントを通して Go コミュニティの発展に寄与できればと思っています 💳

kanmu.co.jp

COO がセッションに登壇します ʕ◔ϖ◔ʔ

今回の GoCon では、カンム COO の @_achiku が登壇します! 13:50 から Track A に登場しますので、みなさんぜひご覧ください!

gocon.jp

オフィスアワーで CTF を開催します ʕ◔ϖ◔ʔ

今回の GoCon も完全リモート開催!Remo で開催される オフィスアワー にてブースを出展させていただきます!

そして前回の GoCon で好評いただいた CTF 、今回も実施します!

Goで書かれたHTTPサーバのバグを見つけて秘密のファイルにアクセスしよう!

Goを読めてHTTPはちょっとわかるぞという人に向けて。問題は当日公開予定、ブースやTwitterで随時ヒントの発表や解説などを行います!

前回の問題と解説は こちら に掲載しています!GoCon 当日までに復習しておくのはいかがでしょうか?

このほかにも

  • カンムやバンドルカードについて聞いてみたい!
  • 登壇していたメンバーと話してみたい!
  • Go についてわいわい話したい!

などなども大歓迎です!Remo のブースに気軽に遊びに来てみてくださいね!

参加登録は connpass から ʕ◔ϖ◔ʔ

gocon.connpass.com

gopher のみなさんとお会いできることを楽しみにしております👋

カンムを支える技術 ~モバイルアプリ編~

カンムのCTOの伊藤です。

カンムではバンドルカード、そしてこれからリリース予定の pool https://pool-card.jp/ においても React Native を採用しています。 実際にどういった環境で開発運用をしているかについて簡単にご紹介します。

React Native の採用理由や経緯については React Native Matsuri 2021 で話したこちらの記事も参考にしてみてください。

speakerdeck.com

基本的な構成技術

  • React Native
  • Redux
  • Flow
  • Storybook
  • Firebase

開発の進め方

普段の開発は GitHub でタスク管理をし、PR を出してレビューするという一般的なスタイルです。 GitHub Projects を利用して進捗を管理していたり、他のチームに今後のリリースに含められる予定のものを共有する目的でアプリのリリースごとにマイルストーンを作成しています。

言語

言語はバンドルカードに関しては JavaScript + Flow 、pool は TypeScript を採用しています。 エコシステムの充実度や新しく入ってくるメンバーの経験などの理由からバンドルカードも TypeScript へ移行したいと考えています。

ビルド・リリース周り

ビルドやリリースに関しては基本的に fastlane で完結させ、それを Bitrise にて実行しています。二段階認証を使用しているApple Developerアカウントと連携することができるのでBitriseを選択しています。

App Store Connect 2FA solved on Bitrise | Bitrise

開発版の社内への配布は DeployGate を利用しています。

CI に関しては社内の既存のリソースとの兼ね合いで、テストや lint などは CircleCI を利用しています。

f:id:kanmu-tech:20211002143621p:plain

アプリのリリース自体はおおよそ週1のサイクルで行っており、コードフリーズをして必要なQAを行ってというサイクルで進めています。

API連携

バンドルカードにおいては、JSON Hyper-Schema から API クライアントの実装を自動生成しそれを利用しています。 バックエンドのAPIサーバーも同じスキーマからリクエスト/レスポンスの構造体やバリデーション実装を自動生成しています。 pool では OpenAPI を採用していますが、基本的にはバンドルカードと同様にクライアント・サーバーどちらもそのスキーマから自動生成しています。

テスト

ロジック部分のテストには Jest を利用しています。すべてを網羅できているわけではありませんが基本的に新規作成する際はテストを追加していくようにしています。
コンポーネントのテストに関しては Snapshot testing を行い、意図しない差分が出ていないかを確認しています。 E2E テストに関してはアプリのフローに SMS 認証が挟まる都合上実現できておらずどのように解決するかを模索中です。

Storybook

いわゆるUIコンポーネントカタログのような使い方をしています。デザイナーも Xcode を使用してアプリをビルドすることで Storybook を参照できるようにしており、いつでも実際の実装を確認することができます。Storybook を起動してもらう際にアップデートなどで様々なトラブルが発生しますが所持していない端末で確認できるようになったので結果的には良かったと思っています。
ライトに確認できるように将来的には社内用に独立したアプリとしてビルドしておきたいと考えてはいます。
使い回さないページなどのコンポーネントも全て Storybook 化しており、これに対して Snapshot testing を行っています。

エラートラッカー/クラッシュレポート

エラートラッキングには Sentry を利用しています。定期的に発生しているエラーをトリアージして issue に転記しながら優先順位をつけて随時対応していっています。 合わせて Firebase Crashlytics も利用しており、Firebase で記録しているイベントに紐付けられて便利なので Sentry の補助的な役割として使っています。

Firebase の他の機能

アプリの行動ログは Firebase Analytics で収集しています。react-navigation の遷移イベントをフックにページ遷移のトラッキングなどもしています。 他には Remote Config を A/B テストや、その他任意のタイミングで文言を切り替えたい場合などに利用しています。

その他

Expo は使っていないか?

バンドルカードを開発した当初 Expo はなかったためそのまま使用せず開発しており、必要に応じてモジュール単位で使用しています。

自前の Native Module はどのくらいあるか?

バンドルカードにおいて、スクリーンショットの制御周りと、ローカル認証の制御のためにすごく小さな Native Module 2 つ管理しています。 ネイティブの機能をゴリゴリ使いたいような類のアプリケーションではないので Native Module を書く機会はかなり少ないです。

おわりに

こう振り返ってみるとかなり素朴な構成でここまでやってきております。 長年運用してきている中での課題も色々見えて来ているというのが現状で、やりたいことは無限にあります。

カンムでは React Native で開発するエンジニアもそうでないエンジニアも絶賛募集しております

kanmu.co.jp

「UXライティングの教科書」の読書会を実施しました

デザイナーのtorimizunoです。 デザイナーメンバーで、今現在のスキルマップと今後できるようになりたいことの共有会を実施したところ、全員に「ライティング」が入っていたので、勉強のために読書会を立ち上げました。

f:id:kanmu-tech:20210913161657p:plain

カンムでは日々勉強会やデータ会などが開催されており、この記事ではその取り組みのひとつとして、今回の読書会を紹介します。

対象の本: UXライティングの教科書 ユーザーの心をひきつけるマイクロコピーの書き方

www.amazon.co.jp

進め方

開催するにあたり、まず会の目的と進め方を定義して参加メンバーに伝えました。

背景

  • アプリなどのプロダクトの文言決めについて、チーム内で議論をする場面が多々ある
  • マイクロコピーというライティングの分野があり、ユーザビリティや顧客エンゲージメントを向上させる文言についてのノウハウが蓄積されている

目的

  • ユーザビリティやUXを向上させる文言やそれを決めるためのノウハウを学習し、文言決めをスムーズに行えるようになる、またはアドバイスできるようになる

メンバー

  • 必須
    • デザイナーメンバー
  • 任意
    • 希望者

せっかくならデザイナー以外でも興味ある人なら誰でも参加していただきたいな…と声をかけたところ、COO・マーケティング・採用・エンジニア・bizdev・CSメンバーも参加の挙手をしてくれて、10人での参加になりました!

f:id:kanmu-tech:20210913160445p:plain

実施方法

初回は読書会参加メンバーの顔合わせも兼ねて背景・目的・実施方法について共有するキックオフを実施しました。 それ以降は下記の内容で各章を実施していきます。

  • 毎週当番が章の要点をまとめて発表・議論する(60min…早く終わり次第解散)
    • 業務に役立ちそうな知見 / 要約
    • 現状のプロダクトとの比較 / プロダクトで実践
    • よく理解できなかった点

また、すべての章が終わったタイミングで、振り返りを実施しました。 自分自身がカンムで読書会を主催するのがはじめてだったのもあり、会自体どうだったのか参加メンバーからの声を吸い上げたかった&参加者で共有したかった、今後の読書会に活かせるナレッジを全員で得られるようにしたかった…のが目的です。

実施してみて

最初にボイス&トーンの章があり、これらがユーザーに与える影響の大きさからライティングの大事さの認識を揃えた後、具体的なライティングの勉強について入る…という本の構成がよかったです。

次に参加者でブランド・ユーザー・現状について改めて議論できる機会があり、新しいメンバーが知らない過去のブランドで考えていたことを知れたり、現時点、今後の話もディスカッションできました。

▼ブランドを体現する言葉について議論したもの f:id:kanmu-tech:20210913160723p:plain

毎週の章では、内容の共有の他、現状プロダクトでどうなっているかを見つめ直し、教科書を踏まえた上でどうあるべきかを全員がその場で考えてディスカッションするムーブが自然発生していったのがとてもよかったと感じました。

プロダクト開発チームの垣根を越えそれぞれの職種ごとの視点の意見交換ができていて、もっとこういう機会を普段のプロダクト開発でも増やしたいなぁ…とも感じました。

▼ディスカッションのメモ f:id:kanmu-tech:20210913161437p:plain

読書会以外の時間でも実施した意味を感じていて、参加者の方とのMTG中に「UXライディングの教科書で登場した〜」というような、読書会から索引された内容の意見が飛び交う瞬間があり、言葉を考える時の判断材料のひとつに取り込まれていっているのを感じています。

読書会を通して、実際にプロダクトの改善施策も何個か走り、ダイアログ・プッシュ文言・新規登録時などのライティング改善にも活かされていっています。

本の自体の感想としては、「教科書」と名がついているのもあってライティングを考慮時に考えるべき視点を体型的に学ぶことができ、エラーメッセージなど細かい点も何を意識して考えるべきかがまとまっているので、デザインを考える上で手元に置いていつでも参照したい本のひとつになりました。

振り返りでの参加メンバーのコメント

  • 文言を考える指針ができたのでよかった
  • 各テーマ毎に視点を絞ってアプリを確認できた
  • 「UXライティングのアレ」みたいな会話でコンテキストを圧縮できているような気がする
  • 本は例がWeb寄り、アプリという限られたスペースを有効活用する場合はどうなるももっと知りたい
  • フリーディスカッションの時間もっと欲しかった
  • デザイナーが学びたいこと=割と誰でも役にたちそう
  • アクセシビリティの視点を持ってなかったので面白かった
  • いろんな人のプロダクトの現状イケてないポイントが知れたのはよかった

今後

振り返りで読書会のやり方自体についても議論があり、その点については本によっていろんな読書会のやり方が考えられそうだなと思いました。

読書会のやり方に対するメンバーのコメント

  • ひとりで読むと大変そうな厚い本の負担が分散できた
  • 要約が大変、でも要約すると考えは整理される、自分は要約だからできた
  • 引用が多いと読書会の意味を考えるが、後でesa(社内wiki)で読めるエッセンスとして見れる観点もある
  • やり方のフォーマットがあれば楽かもしれない
  • 本に載ってない知識を引っ張り出せたのがよかった

今後はこれらのコメントを参考に、また別の分野でも、読書会や勉強会を実施していきたいです!

カンムでは学習と共有に一緒に取り組む仲間を募集しています。

team.kanmu.co.jp

カンム流『朝会』をやってみたら予想以上にウケが良かった件

はじめに

f:id:kanmu-tech:20210910182508p:plain

こんにちは、カンムでバンドルカードの機械学習部分を担当しているfkubotaです。
今回は、カンムで行っている雑談朝会について書こうと思います。
いきなりですが朝会や雑談会などを普段やっていますか?
コロナの影響でリモートになって「コミュニケーションが足りてない!朝会やるぞ!」という感じではじめた会社、チームは多いのではないでしょうか。
僕も前職含めコロナで失われたコミュニケーションを取り戻したいというモチベーションの朝会に参加していました。
ただこの朝会、とても運用難しいですよね。
勢いよくはじめたものの「この会意味あるの?」 と各人が自問してしまうような会は多くあるはずです。
この記事ではリモートワークで失われてしまった愛すべき雑談を取り戻したいという思いではじめた朝会運用について紹介したいと思います。
僕は朝会は大きく分けて二種類あると考えています。

  • タスクの共有
  • コミュニケーションを増やす

今回紹介する朝会はコミュニケーションに比重を全振りしているので仕事の生産性がどうのこうのという話は一切出てきませんのでご了承ください。(巡り巡って生産性があがる可能性は十分ありますが)

朝会の運用は難しい

f:id:kanmu-tech:20210910182658p:plain ここで一度、朝会の難かしさと解決したい問題点を洗い出します。

  • 朝会パターン1: 業務報告会&ついでに雑談
    • これは一番多いパターンではないでしょうか。
    • 昨日やったこと、今日やること、困ってることを各自報告するようなパターンです。
    • 雑談あればついでにやるような感じです。
    • このパターンは慣れてくると「キノウハ、ナニナニシマシター。キョウモオナジデース。イジョウデース。」のようにこなすだけの形骸化した朝会になりがちです。周りの人も本当に真面目に聞いているのか怪しいところです。
    • 形骸化した朝会は早めに時間がすぎることが好ましいため雑談は減る傾向にあります。よって雑談は自然と少なくなるでしょう。
  • 朝会パターン2: 雑談会(強制参加)
    • 集まって雑談しようの会です。
    • 毎日同じメンバーで話すので雑談はすぐに尽きます。
    • よく喋る人がたくさん喋って聞き専みたいな人が生まれるのも必然かもしれません。
    • それとそもそもなのですが、雑談があまり得意でない人がいるのも考慮したいところです。
  • 朝会パターン3: 雑談会(任意)
    • 最初は盛り上がりますが、徐々に人が来なくなります。
    • きっと「数人いるなら入ろう」の精神の人が多いはずなので牽制しあって結局誰も入らないパターンですね。
    • 静かになくなっていく悲しい会になりやすいと思います。

なんとなく想像がついたところで上記から戦わなければいけない問題点を洗い出します。

  • 形骸化させない
  • 毎回同じメンバーにさせない
  • 強制参加にしない
  • 参加者はできるだけ発言できるようにする

これともう一つ要素を追加します。コロナ禍に転職した関係構築に四苦八苦しているであろう入社したての人への配慮も入れておきます。

  • 入社したての人への配慮 をする

考えた朝会のカタチ

f:id:kanmu-tech:20210910182831p:plain

それでは、上記の問題を同時に解決する策を数ヶ月コツコツと考えた結果を紹介します。
僕の中では紆余曲折あったのですが、結論だけ述べます。
以下のような方法を取っています。(Slack運用を想定)

  • pj-asakai などの朝会専用チャンネルを作成
  • 朝会に参加したい人はここに入る
  • 活動は、火曜日と木曜日の朝に15分
  • google meet を使用し、できるだけカメラONにしている
  • 聞き専はNG
  • 参加メンバー は多くても6人ぐらい <--- これ大事
    • 固定メンバー
      • 直近3ヶ月以内入社組(3, 4人程度想定)
      • ホスト1人
    • ランダムメンバー
      • チャンネルに所属しているメンバーからランダムに2人を選ぶ(SlackAppで実行。後ほど紹介します。)

こんな感じです。ランダムに選ばれるメンバーがいることが大事なポイントです。
(具体的な人数は組織の大きさなどに応じて適宜変える必要はあります)

さきほどあげた問題点と照らし合わせます

  • 形骸化させない
    • 週に2回15分だけなのでちょっと物足りないぐらいで終わる。(無言の気まずい時間が最小限)
    • メンバーが毎回変わる
  • 毎回同じメンバーにさせない
    • ランダム枠を用意している
  • 強制参加にしない
    • ランダムに選ばれる人は、pj-asakaiチャンネル に所属している人だけ なのでチャンネルに参加した人は参加したい意思表示をしたことになります。
    • チャンネルに参加しない限りランダムで選ばれることはありません。
  • 参加者はできるだけ発言できるようにする
    • 少人数制かつ聞き専NGなので話しやすい
  • 入社したての人への配慮 をする
    • 直近3ヶ月以内に入社した人は固定メンバーとしている
    • 社内の人なら誰でもOKなので普段仕事で関わらない人とも雑談を楽しめる

こんな感じです。あげた問題にしっかり対処できています! :)

やってみてどうだったか

このアイデアをながいこと温めてカンムで開催される月に1度の TechDayで発表しました。
共感してくれる人が多く、社員39名(2021年9月時点)のうち19人が朝会チャンネルにさっそく入ってくれました。
(こういうイベントに飛びつく人が多いのもカンムの楽しいところ)

評判は結構いいです。僕自身も雑談たくさんできてウキウキです。
特に直近入社組は仕事で関わらない人と雑談できるということで喜んでいただけているようです。
開始してまだ2ヶ月弱ですが今の所毎回大盛りあがりです。
マニアックな話題が出て時間足りないよーって感じで惜しく終わるのも続いているポイントなのかもしれません。

  • 話題例
    • メガネの話
    • 引っ越しの話
    • 今年のベストバイ!の話
    • などなど

会後のslackでワイワイも楽しいですね。

f:id:kanmu-tech:20210913173041p:plain


f:id:kanmu-tech:20210913173108p:plain


f:id:kanmu-tech:20210913173152p:plain

紹介は以上です。
結構楽しいので雑談会を定期的に実行したい場合は参考にしてみてください!

おまけ(ランダムにメンバー選ぶSlackApp)

ランダムにメンバーを選ぶ時にいろいろやり方があると思うのですが、カンムでは Picker というSlack Appを使っています。 使い方は簡単で
/pick other 朝会だよ! を実行すれば、チャンネルに属している人の中から一人が選ばれてメンションされます。
(otherは任意のタスク的な意味なのであまり気にしないでください。)

このアプリはかなり融通がきく仕様になっていて、

  • 固定メンバーのA,B,Cさんはランダム候補から常に除く
  • Dさんを一度だけ除く
  • 2人選ぶ

などのオプションを付与できます。
/pick help を見れば簡単にわかるのでなにか困ったときにはヘルプを見てみてください。
最後にコマンド実行例画像を添えて終わりたいと思います。

/pick ot :asakai: -choose 2 (←2人選ぶ) コマンド実行例

f:id:kanmu-tech:20210910181802p:plain
picker

お決まりの

積極採用中です!!

kanmu.co.jp