生涯未熟

生涯未熟

プログラミングをちょこちょこと。

SRE Kaigiはなぜ大吉祥寺.pmにスポンサーするに至ったか?

吉祥寺.pmについての25個の小さな話、またはMagnolia.Kの雑記 Advent Calendar 2025の25日目の記事になります。

adventar.org

なんか最終日だけ空いてたので埋めることにしました。埋めようとして気付いたのですが、もしかして最終日をMagnoliaさんに記事書いてもらうために皆さん空けていたのでは・・・?と思ったりしましたが、遠慮の塊みたいで気持ち悪いの埋めちゃいます。

吉祥寺.pmとの関わり

吉祥寺.pm自体に参加したことはなかったのですが、「なんか面白そうなイベントあるな〜〜〜」とずっと思っていたものの「Perlのイベントなんでしょ?Perl知らんしな〜〜〜」という印象を引きずりながら盛り上がっている様を眺めていました。
しかし、2024年の大吉祥寺.pmの時にイベント概要を覗いて「あ、Perlという制限はないのか」と気付くに至りました。遅い。

で、去年の大吉祥寺.pmはちょっと行くことが叶わなかったので、次回こそは!という気持ちを1年引きずっておりました。

ちなみにmagnoliaさん自体はかなり前からフォローしてたのですが、最初の絡みを探したら訳分からなくて笑っちゃいました。

スポンサーという手があったか

そんなこんなで大吉祥寺.pm 2025が開催されるということで、調べてみるとなんとスポンサー募集もやってるではないですか!

普通に参加者として参戦する予定だったのですが、ちょうどSRE Kaigiの認知を向上させたいと思っていた矢先だったので、これ幸いとスポンサーとして申し込むことにしました。

さて、ここでなんでスポンサーとして申し込んだの?って話ですが、2つ理由がありまして「参加者の多様さ」「登壇枠というアピールの場」が決め手でした。

参加者の多様さ

協賛するにあたって、2024年の大吉祥寺.pmの参加者を眺めていたですが、本当に種々様々な方が参加されていますよね。例えば〇〇界隈、みたいなひとかたまりな方たちが集まっているのではなく、色んな界隈で見たことある人が集まっています。間口が広い!

大吉祥寺.pm - 参加者・申込者一覧 - connpass

で、この参加者の多様さが今回スポンサーをするに当たっての決め手ではありました。SRE Kaigiを何故やっているのか?というと、SRE界隈をより盛り上げるという面もありつつ、「SREってなんやねん」っていう方たちに少しでもSREのことを知っていただくという面もあるんですよね。そういった意味で、様々な界隈に対して「SREのコミュニティでこんなことやってるぜ!」と訴えかける良いきっかけになるなと。

登壇枠というアピールの場

で、そのアピールの場をいただける、というのも決め手の一つでした。300人近くの人たちの中の1名でもSREに興味を持っていただけたらなという淡い気持ちがありつつ、自分自身がそこまで大きな舞台で喋ったことがないので、経験を積みたいというお気持ちも少しばかりあったり・・・

話下手ではあるので、どこまでSREに対する気持ちが聞いていただいた方に届いたのかは謎ですが、非常によい経験になりました!300人に見られて喋る機会はなかなかないぞ!

参加して分かった吉祥寺.pmの魅力

吉祥寺.pmノービスな自分が言うのも烏滸がましいですが、magnoliaさんの魅力がイコール吉祥寺.pmの魅力に繋がっているのかなと思いました。
参加者の多様さという点がありましたが、これもmagnoliaさんの人望が様々な界隈で発揮されていて、それが波及しこれだけの人を集められているのかなという。

で、そのmagnoliaさんの魅力に少しでも触れるべく、大吉祥寺.pmの時に「落ち着いたら飲みに行きましょう!」と ~無理くり~ お誘いして、吉祥寺で飲むことに成功しました。
飲みの席では本当に様々な示唆を与えていただき、めちゃくちゃ貴重な体験ができました!magnoliaさん、良ければまた飲みに行きましょう🍻

皆さんも誘いましょう(ぇ

おわり

ということで、大吉祥寺.pmへスポンサーをしてみたというお話でした。次回の開催はあるのかはまだ未定だと思いますが、開催されましたら参加するのをオススメしますし、スポンサーできる方はスポンサーするのがオススメです!

素敵な体験をありがとう!吉祥寺.pm!🙌

カンファレンスのオーガナイザーをやったらメモ魔になった

技術イベント・カンファレンス運営のノウハウ Advent Calendar 2025ということで、21日目を担当いたします。

adventar.org

正直、イベント運営に関する真面目な部分のお話は皆さんがされていると思いますので、自分からは初めてオーガナイザーをやってみて習慣が身に付いたお話をしようかなと思います。

あんた誰かね?

しょっさんと申します。SRE Kaigiのオーガナイザーとして、SRE Kaigi 2025を開催しました。それ以外にも「ゆるSRE勉強会」の共同運営や、「SRE Magazine」の編集長をやっていたり、「Observability Conference Tokyo 2025」のコアスタッフもやったりしました。
なんかSREの界隈をチョロチョロしているおじさんという認識で大丈夫です。

メモ魔になった

元々自分はあんまりメモを取らない人間でした。「消えてしまった記憶は要らない記憶」をモットーにあまり記録を残さないという主義で、自分の写真を残すのも正直あまり好きではないというくらいです。

で、そんな人間がカンファレンス運営をやってメモ魔になってしまいました。それはなぜか?

答えは明白で

  • 「膨れ上がるタスクの管理」
  • 「溢れ出るアイデアの書き留め」

この2つをなんとかするためにもメモをしまくるしかない、という結論に至ったからです。

膨れ上がるタスクの管理

これは初回開催かつ、自分が様々なタスクを初回のうちに体験しておかないといけないという2つの理由が起因となっているもので、とにかく初回開催では「使い回せる何か」がないので全部一から用意しなくてはいけません。
ロードマップ、チーム構成、コンテンツの準備、果てはスポンサー様・登壇者様に送るメール文言に至るまで多種多様なものを0から生み出します。
そうなるとまぁとにかく手を動かさなきゃならん、となりますね?

あと、これは自分の中で「やってみせ、言って聞かせて、させてみせ、ほめてやらねば、人は動かじ」の精神が根付いているので、まずは自分が出来なきゃダメだよね?ということで、いろんなチームのタスクをグイグイやりました。
ちなみにAdobe illustratorもちょいちょい覚えましたし、Premiere Proでの動画編集もちびっと覚えました。SRE Kaigi 2025の公式サイトのデザインなど、結構デザイン周りも手を動かしました。

で、こんな色んなことをやってたらまぁタスクが爆発的に増えるんですわな。

タスクが爆発的に増えても漏れがないようにしなければ、ということでタスクが生まれたら即ObsidianのTODOリストにババっとメモる癖をつけました。

これはもう自分のズボラさが生んだアレなのですが、例えばGitHubのissueでタスクを管理するだとか、カンバンボードでタスクを管理するだとかが只管に苦手なので、こんくらいの雑さでパパッと管理できるのが楽だったんですよね。形式も好きに変えれるし。

というわけで、こんな感じでタスク管理のためにめっちゃメモってました。

溢れ出るアイデアの書き留め

で、どちらかといえばこっちがメインで、カンファレンスの初回開催は真っ白いキャンパスに好きに描けよって言われてるようなもので、もう本当に自分がこうしたい!と思ったことを実現できます。(リソースが許す限りは)
そうなってくると、「どうやったら参加者の方に楽しんでいただけて、スポンサー様・登壇者様にとっても喜んでもらえるカンファレンスにできるか?」のアイデアが無限に湧いてくるんですよ。

SRE Kaigi 2025の時のそういうアイデアを書き留めていたメモ帳見てたら、書いたり消したりで多分1万文字超すくらいの分量で書いてました。そのくらい「あれやったら面白そう!」「これやったら喜んでくれそう!」が溢れてきます。

さて、こういうアイデアってのはいつ何時降ってくるか分かりません。中国の故事に"三上"というのがございますが、「馬上」「枕上」「厠上」という3つのシチュエーションは考えに耽りやすく、アイデアが降ってきやすいと言われるもので、それぞれ「移動中」「寝る前」「トイレの時」のシチュエーションを指します。
自分は特に「移動中」「寝る前」が降ってきやすく、電車に乗っているときに敢えてスマホを見ずにボーっと景色を眺めていたり、寝る前にゴロゴロしていると「あ、これやると面白そう」ってのがめっちゃありました。で、そういう時にスマホからシュババッとメモれる環境があると良いんですな。

それが自分にとってObsidianでパパっとメモるという方法でした。これも本当に乱雑でもいいので書き留めておいて、日を空けてから「やっぱこれいいな」と思ったら採用、「いや、無理っしょ」となったら不採用、と書き足したり消したりの繰り返しができるように、公園の砂場遊びくらいの気楽な感じで思案の種にしていました。

こういう気軽さをメモに求めるのが自分にとって凄いフィットしたんですよね。

あとは、これは自分の性格に由来するものなのですが、考えているうちに別のことを考えて、その考えている時にまた別の考えが湧いてきて・・・という思考の連鎖が変に起こっちゃうので、いつでもバックトラックできるように考えを巡らせる時も逐一メモるようにしてました。
これをしとかないと「あれ?3巡前くらいに考えてたことってなんだっけ?」みたいな感じになっちゃうので。

メモ魔になった結果

そんなこんなで、Obsidianにモリモリと文字が積み上がるわけですが、少なくとも自分にとっては精神的な効果がめちゃくちゃありました。どういうことかというと、頭の中身をメモにある程度移しておくと「あれやったっけ?」「これって既に考えたっけ?」「なんでダメって思ったんだっけ?」というのが検索することですぐに分かって、モヤモヤすることや不安が少なくなったのが大きな理由です。

もう一つ、こういうのを残しておくとある種自分にとっての資産になるので、色々な場面で使うことができます。例えば、登壇する時の引き出しにしたりだとか、新しいアイデアを考える時の芽として使ったり。何がどう転じて有用性を発揮するか分からんので、メモって損なしだとは思ってます。

とりあえずメモってみよ

世の中には「メモの技術」みたいな某かはあると思いますが、まずはそんなものほっぽって自分の一番手に馴染みやすいスタイルを追求するのが良いと思います。考えに考えて結局やってみてダメでしたはかなりやる気が挫かれるので。そんなくらいなら、とりあえず形式は何でもいいのでメモってみるところから始めてみるのが良いと思います。

もし、意識的にやったことない人はやってみましょう💪

【宣伝】

Conference Owners Cafeというイベント主催者向けのDiscordが爆誕しました!👏 お悩み事とか情報とかを共有していくコミュニティになるっぽいので、興味のある方はご参加を!👇️

discord.gg

IT系勉強会 会場まとめのスプシも作ったので、所属社がイベントスペースのお貸し出しとかしているところは書いてもらえると助かります!🙏

docs.google.com

町田.pm#4と忘年会に参加しました

machidapm.connpass.com

今年最後の町田.pmが開催されましたので行ってきました。わいわい。

今回はSRE MagazineでSRE Weeklyのように国内外の記事を紹介しようという感じのことをやりたくて、記事を集めたりしていました。
いくつか良さそうな記事が見つかったので、次号で紹介しようかなと。

もくもく作業が終わったら次は町田.pm忘年会のお時間。

オダサガの有名餃子店、萬金へ。

遺産相続の話からLTの歴史、昭和特撮から「エンジニアリングの歴史は知れるが当時の熱情は知ることができない」という話まで、様々な話が繰り広げられました。たのしい。
「町田」という括りで集まっているので、普段お会いできない方たちから色々なお話が聞けるのが本当に体験として良いんですよね。これがあるから地域勉強会はよい。

Xで相互になってるけど1度も会ったこと無かった沼さんに会えたのも良かった。年齢も近いというのが知れてまたびっくり。

ということで大満足の忘年会でした。町田.pmを始めてくださったSongmuさんに感謝しかありません🙏
来年も顔出します!

Slack botを使ったGoogle Cloudの一時権限付与をOpenAI APIで実現してみた

はじめに

この記事は「MIXI DEVELOPERS Advent Calendar 2025」14日目の記事になります。
こんにちはこんにちは、しょっさん( @syossan27 )です。

今回は、より適切な権限管理を行うために、一時権限付与プロセスをAIを活用して便利にしてみた、という内容をご紹介いたします。

背景と課題

SRE にとって、サービスのセキュリティを担保するための権限管理は非常に重要です。 弊チームでは、 Slack botとOpenAI API を組み合わせ、Google Cloud プロジェクトの一時権限を自然言語で付与する仕組み を開発しました。

従来の権限付与の問題点

従来の一時権限付与はSlackでスラッシュコマンドを利用して、例えば以下のように実行していました。

/fansta grant roles/container.developer hoge@example.com

ただし、一時権限付与のたびにこれを思い出して実行してもらうのは中々開発チームにとって骨ではあります。
また「やりたい作業に必要な権限はどれか?」という質問がSREsに寄せられることもしばしばあり、運用上の壁となっていました。

目指した解決策

これらの課題を解決するために、以下のような要件を設定しました:

  • 自然言語での権限要求: 「Compute Engineの管理権限を〇〇さんに付与して」のような自然な表現で権限を要求
  • 一時的な権限付与: これまでと変わらず、有効期限付きの権限付与(デフォルト7日間)
  • 適切な権限の付与: 自然言語で指定した適切な権限を検索・付与
  • 承認フロー: 権限付与前の確認プロセス

こうした仕組みによって、開発チームとSREsのお互いにとって嬉しい状態を実現しようとしました。

また、自然言語での操作を許可する以上、意図しない権限や対象者を解釈してしまうリスクがあります。 そのため、最終的には人間の承認を挟んで安全に実行できるよう設計しました。

システム概要

アーキテクチャ

システムは以下のコンポーネントで構成されています:

コンポーネントごとの動きとしてはザッとこのようになります。

  1. Slack bot handler: Slackのメンションイベントを受信し、Pub/Subメッセージを送信。Slack bot は 3 秒以内に応答が必要なため、この時点では「処理中です」と返す
  2. Slack bot backend: Pub/Subメッセージを受信し、OpenAI API(Responses API)を呼び出す
  3. OpenAI API(Responses API: 自然言語を解析し、必要に応じて Function Calling で一時権限付与関数を呼び出す
  4. Google Cloud IAM API: 条件付きロールバインディングを使って一時権限を付与

それでは、次は実装の詳細を見ていきましょう。

実装詳細

1. Slackイベントの処理

まず、Slackからのメンション(@bot)イベントを受信するCloud Functionsの実装になります。

func handleSlackEvent(w http.ResponseWriter, r *http.Request) {
    // Slackイベントの解析
    var eventCallback SlackEventCallback
    if err := json.NewDecoder(bytes.NewReader(bodyBytes)).Decode(&eventCallback); err != nil {
        log.Printf("Error decoding JSON: %v", err)
        return
    }

    switch eventCallback.Type {
    case "event_callback":
        var appMentionEvent AppMentionEvent
        if err := json.Unmarshal(eventCallback.Event, &appMentionEvent); err == nil {
            if appMentionEvent.Type == "app_mention" {
                // Pub/Subに送信
                publishToPubSub(args, event.Channel, event.User)
            }
        }
    }
}

まずはSlackから飛んできたリクエスト内容を読み取り、そのままSlack bot backendへPub/Subを通して投げます。
ここには記載してませんが、投げた後はSlackへ「処理中のため、ちょっと待っててね」というメッセージをメンション付きで投稿しています。
Slack bot handlerの役割はここで終わりで、この先はSlack bot backendの役目になります。

2. OpenAI APIとの連携

Slack bot backendでは、まずはOpenAI APIを使用して自然言語を構造化データに変換します。
Azure OpenAIのResponses APIを活用し、Function Callingの仕組みを利用しています。

func callAzureOpenAI(question string) (*AzureOpenAIResponse, error) {
    client := openai.NewClient(
        azure.WithAPIKey(apiKey),
        option.WithBaseURL(endpoint+"/openai/v1"),
    )

    // Function定義
    tools := []responses.ToolUnionParam{
        {
            OfFunction: &responses.FunctionToolParam{
                Name:        "grantTemporaryPermission",
                Description: "ユーザーに一時的なIAMロールを付与します。",
                Parameters: openai.FunctionParameters{
                    "type": "object",
                    "properties": map[string]interface{}{
                        "role": map[string]interface{}{
                            "type": "string",
                            "description": "付与するGoogle Cloud IAMのロール名",
                        },
                        "members": map[string]interface{}{
                            "type": "array",
                            "description": "権限を付与する対象ユーザー",
                        },
                    },
                },
            },
        },
    }

    resp, err := client.Responses.New(ctx, responses.ResponseNewParams{
        Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(question)},
        Model: openai.ChatModelGPT4o,
        Tools: tools,
    })

    return parseResponse(resp)
}

ここではFunction Callingに利用するFunction定義やResponses APIの定義を書いてたりします。
Function Callingについてご存じない方への簡単な説明として「プロンプトの内容から実行が必要とされる外部関数を呼び出してくれる」という機能になります。
今回で言うと、「権限の付与」的な意味合いを持つプロンプトだと grantTemporaryPermission の関数実行が走るという感じですね。

3. 自然言語処理の仕組み

OpenAI APIには、以下の情報を含むFunction定義を提供しています:

■ ロール名の変換

例:

  • 入力 → Compute Engine の管理権限
  • 出力 → roles/compute.instanceAdmin.v1

この変換のために、Google CloudのIAMロール一覧をVector Storeに格納し、File Search機能を活用しています。一覧に記載されているロールのdescriptionが推測精度に大きく寄与します。

以下はVector Storeに格納するために別途作成したスクリプトになります。

vector_store = client.vector_stores.create(
    name="Financial Statements",
    chunking_strategy={
        "type": "static",
        "static": {
            "max_chunk_size_tokens": 300,
            "chunk_overlap_tokens": 20
        }
    }
)

file_batch = client.vector_stores.file_batches.upload_and_poll(
    vector_store_id=vector_store.id,
    files=[open("roles.txt", "rb")]
)

Vector Storeに格納するファイルは gcloud iam roles list で取得してきたIAMについての説明付きの一覧になります。以下のような感じで出力されているので、こちらの内容をもとに付与したい権限を推察させるわけですね。

description: Grants ability to create Workstation resources.
etag: AA==
name: roles/workstations.workstationCreator
stage: GA
title: Cloud Workstations Creator
---
description: Grants ability to create workstations with exemption from max_usable_workstations
  Limit.
etag: AA==
name: roles/workstations.workstationLimitExemptedCreator
stage: GA
title: Cloud Workstations Limit Exempted Creator

また、descriptionがかなり推察に寄与する要素ですので、実際は以下のように作っております。

"role": map[string]interface{}{
    "type": "string",
    "description": "付与するGoogle Cloud IAMのロール名を指定します。" +
        "例えば「roles/compute.instanceAdmin.v1」や、自然言語で「Compute Engineのインスタンス管理者権限」などが指定されます。" +
        "自然言語で指定された場合はFile Searchを行い、適切なロールに変換してください。" +
        "例として「Compute Engineのインスタンス管理者権限」を指定された場合には「roles/compute.instanceAdmin.v1」といった形式に変換してください。",
},

■ ユーザー名の変換

例:

  • 入力 →「〇〇さん」「しょっさん」
  • 出力 → user:hoge@example.com

Function定義内に名前とメールアドレスの対応表を埋め込み、変換を実現しています。
自然言語としての広がりを持たせるためにニックネームが浸透している方はニックネームでも対象とできるようにしています。

こちらもdescriptionは以下のように作っております。

"members": map[string]interface{}{
    "type": "array",
    "items": map[string]interface{}{
        "type": "string",
    },
    "description": "権限を付与する対象ユーザーが1人、もしくは複数人が指定されます。" +
        "例えば「〇〇さん」といった名前が指定されます。" +
        "この名前をもとに、紐づいたGoogle Cloud IAMのユーザーアカウントを指定する必要があります。" +
        "例えば「〇〇さん」を指定されたときには「user:hoge@example.com」といった形式に変換してください。" +
        "複数人指定された場合は、変換して配列で指定してください。" +
        "以下にフルネーム(ふりがな, ニックネーム)とユーザーアカウントの対応表を示しますので、変換の参考にしてください。\n\n" +
        "```\n" +
        "山田 太郎(やまだ たろう): user:taro.yamada@example.com\n" +
        "井上 翔太(いのうえ しょうた、しょっさん): user:syossan27@example.com\n" +
        "```\n",
},

ニックネームに関しては特に調整せずとも、不安定ながら推察してユーザーを選別してくれました。
しかし、より確実性を持たせるために氏名⇔ニックネームの情報をdescriptionに明記しています。

4. 承認フロー

最後に、権限付与前にSlackのインタラクティブボタンを使用した承認フローの実装です。
人によって確認待ちかどうか?を判定するために状態をCloud Storageに保存して簡易的に判断しています。

func showConfirmationMessage(channelID, userID, functionName, functionArgs string) {
    // 確認IDを生成
    confirmationID := generateConfirmationID()

    // 確認待ち状態をCloud Storageに保存
    saveConfirmationToStorage(confirmationID, channelID, userID, functionName, functionArgs)

    // インタラクティブボタン付きメッセージを送信
    attachment := slack.Attachment{
        CallbackID: confirmationID,
        Title:      "以下の操作を実行しますか?",
        Text:       generateFunctionDescription(functionName, functionArgs),
        Actions: []slack.AttachmentAction{
            {Name: "confirm", Text: "はい", Type: "button"},
            {Name: "cancel", Text: "いいえ", Type: "button"},
        },
    }

    api.PostMessage(channelID, slack.MsgOptionAttachments(attachment))
}

5. 権限付与の実行

確認が完了すると、Google Cloud IAM APIを使用して実際の権限付与を実行します。

func grantTemporaryPermission(channelID, userID string, args string) {
    // 期限付きの条件を設定(7日間)
    expireTime := time.Now().Add(168 * time.Hour).Format(time.RFC3339)
    condition := &cloudresourcemanager.Expr{
        Title:       "Temporary Access",
        Description: "Access expires after 7 days",
        Expression:  fmt.Sprintf("request.time < timestamp('%s')", expireTime),
    }

    // IAMポリシーの更新
    service, _ := cloudresourcemanager.NewService(ctx)
    policy, _ := service.Projects.GetIamPolicy(projectID, request).Do()

    // 条件付きバインディングを追加
    updatedBindings = append(updatedBindings, &cloudresourcemanager.Binding{
        Role:      role,
        Members:   members,
        Condition: condition,
    })

    policy.Bindings = updatedBindings
    service.Projects.SetIamPolicy(projectID, &cloudresourcemanager.SetIamPolicyRequest{
        Policy: policy,
    }).Do()
}

Google CloudのIAMでは 条件付きロール バインディング を利用して一時的な権限を付与することが出来ます。

一時的な権限はチームメンバーで付与できるようにSlack botを介して、恒久的な権限はIaCリポジトリからTerraformを介して付与するように使い分けていたりします。

実際の使用例

使用法

@fansta-bot Compute Engineの管理権限をしょっさんに付与して

この入力に対して、こちらの機能は以下のように動作します:

  1. OpenAI APIが「Compute Engineの管理権限」を roles/compute.instanceAdmin.v1 に変換
  2. 「しょっさん」を user:syossan27@example.com に変換
  3. 承認メッセージをメンション付きで投稿
  4. 承認後、7日間の期限付きで対象ユーザーに権限を付与

また、以下のように複数人への付与も可能です。お手伝い頂いているQAチームへ一時権限を付与することがあるので、チームの複数人に付与できるようにしてあるのです。

@fansta-bot Cloud SQLの管理権限を〇〇さんとしょっさんに付与して

一応、モザイク多めですが実際のスクショもぺたり。

まとめ

というわけで、今回開発したSlack botを使った一時権限付与機能のお話でした。
OpenAI API自然言語処理をSlack botとかけ合わせて活用することで、従来の利用に少し難があった機能を大幅に簡素化できました。

特に以下の点が重要な成果です:

  1. 自然言語を利用することでの簡便性: 知識を必要とせず、誰でも直感的に使用可能
  2. 付与対象者のメールアドレス特定や、必要な権限の検索を自動化: 手動でやらなくてはいけないことを可能な限り最小限に抑制

あと、ここまで書いておいて気付いたのですが自分用に権限検索機能も欲しくなってきました。Google Cloudで権限付与する時に、「あれ?どれ付与すれば良いんだっけ?」ってたまになるので。

今回のように、SREの現場ではこのようにAIを有効活用して、よりDXの改善や自分たちのSRE活動の円滑化がしやすい世の中になりました。今後もAIを活用した運用自動化の取り組みを進めていく予定です!

ということで、開発チームが使いやすいように一時権限付与機能を使いやすくしてみたよという記事でした。この事例が何かの参考になれば幸いです!🙏