はじめに
業務で AWS を使って開発していますが、セキュリティはずっと「なんとなく気をつけている」程度でした。.gitignore で機密情報は Git に上げないようにして、シークレットは Secrets Manager に入れて。それで対策できているつもりでいた、というのが正直なところです。でも、自分の作った環境が攻撃者から見てどう見えているのかまでは、考えたことがありませんでした。
そんな中、AWS に特化した CTF(Capture The Flag)の存在を知り、手を動かす系のイベントが好きなこともあり、初参加してみました(参加イベント:Security-JAWS DAYS 〜10th Anniversary Event〜 Day2 の CTF)。イベントは、4 時間以内に架空企業の AWS 環境へ侵入して情報を集めるところから、CloudTrail でのフォレンジック調査まで、攻撃側から防御側まで通しで体験できる構成でした。
結論から書くと、初参加でも全問解き切ることはできました。ただ、解き終わってからの方が学びは多かったです。他人事では終えられない箇所がいくつもあり、イベントが終わった後も、関連する情報や対策を調べてみました。
今回扱う 5 つのテーマは、正直どれも「なんとなく良くないことだ」とは分かっていたものでした。でも、具体的にどんなリスクがあって、なぜ良くないのかまでは、あまり踏み込んで考えられていませんでした。今回の CTF は、その「なぜ」を自分の手を動かして確かめる、いいきっかけになったと思います。
本記事は、その CTF とその後調べたことを、AWS でシークレットが残ってしまう 5 つの典型パターンとして整理したものです。
公開リソース ── .env がそこにあった
.envファイルはアプリケーションの環境変数を管理するファイルです。 データベースのパスワードやAPIキーが書かれることが多く、Webサーバーの設定ミスで公開されてしまうケースが後を絶ちません。 TechVault社のWebサーバーから.envファイルを探してみよう。
初心者でもすぐ取れた機密情報
問題文に「Webサーバーの設定ミスで公開されてしまう」とあったので、curl 叩けば .env の環境変数見れるんじゃないかと、安易に考えて実際やってみました。すると、.env ファイルが返ってきて、中から AWS のアクセスキーが取得できてしまいました。
最初はよく分からず挑んでいた私でしたが、これについては意外とすんなり解けてしまい、喜びより攻撃の手軽さの方が印象に残りました。
なぜこれが成立したのか
そもそもの問題は、AWS アクセスキーみたいな機密情報を .env に書いて、それを Web から直接アクセスできる場所に置いてしまっていたことです。
ただ、もっと根っこを辿ると、長期有効の AWS アクセスキーを使うことが問題でした。漏れたら困るものをファイルに置いている時点で、.env をどこに隠そうが対策としては弱いわけです。
これは CTF の中だけの話ではありません。調べてみると、Palo Alto Networks の Unit 42 が、約11万のドメインから公開状態の .env を収集し、9万件以上の環境変数が漏洩し、大規模な恐喝行為が可能になったことを報告していました(Unit 42)。攻撃者は機械的に世界中をスキャンして回っているので、「うちは目立たないから大丈夫」は通用しません。
CTF 後に調べた対策
イベント後に対策を調べてみたら、自分が知らなかった選択肢がいくつも出てきました。
そもそも AWS のベストプラクティスでは、EC2 や Lambda、ECS から AWS API を叩くときは、IAM ユーザーのアクセスキーではなく IAM ロールを使うことが推奨されています。ロールなら一時クレデンシャルが自動で発行・更新されるので、そもそもファイルに「置いておく」必要がなくなります。AWS の外(オンプレや外部 CI など)からアクセスするときも、IAM Roles Anywhere で同じことができます。
それでも長期キーをどうしても使わざるを得ない場合は、定期的なローテーションが必要になりますが、AWS Config Rule の access-keys-rotated で「90日以上ローテーションされていないキー」を自動検出できます。「使わない」、使うとしても「自動で監視する」という二段構えの体制が大切です。
さらに、Git リポジトリへのシークレット混入を検知する git-secrets(AWS Labs 製)や gitleaks、trufflehog といったツールもあります。これらは次の章(Git履歴)でもっと深く触れますが、攻撃者の視点に立って初めて、自分の知らない防御の世界があったことに気づかされました。
実務で意識しておきたいこと
基本的な対策(.env を Git 管理から外す、長期キーを避ける)ができていても、それを検知・監視する仕組み(git-secrets や Config Rule など)まで押さえておくと、より安心です。手を動かして攻撃を体験して初めて、こうした選択肢の存在を実感できた気がします。
「やれているから大丈夫」と思える状態と、「対策の引き出しを持っている」状態は別物だな、というのが、この章での一番の気づきでした。
✅ この章のポイント
.envを Web から直接見える場所に置くと、curl 一発で中身を取られる- 本質的な問題は「長期アクセスキーを使っていること」、隠し場所ではない
- IAM ロール化で長期キーそのものを無くすのが本筋
Git履歴 ── 「消したはず」が消えていない
ポータルのフッターに TechVault 社の GitHub リポジトリへのリンクが書いてあった。 「オープンソースで透明性を示す」つもりで公開したらしいが…… コミット履歴を掘り下げると、消したはずの情報が残っていることがある。
Git を遡るだけで取れてしまった
誤って過去に情報をコミットしてしまっていそうだから、コミット履歴を漁ってみたら見つかりそうだな、と問題を見て気づけました。実際に git log --all -p で過去のコミットを掘ると、削除されたはずの .env ファイルがそのまま残っていて、AWS キーも一緒に発掘できました。
糸口が見えてからは、Claude に log を丸々貼り付けて探してもらったところ、こちらもすんなり見つかってしまいました。自分も含めて「うっかりコミット」してしまうことは現実に起こりうるので、少し怖くもありました。
なぜこれが成立したのか
Git は分散バージョン管理システムなので、ファイルを「削除するコミット」を作っても、過去のコミットからそのファイルは消えません。新しい履歴を追加するだけです。つまり、機密情報をうっかりコミットしてしまった瞬間に、それは永遠に履歴の中に残り続けます(意図的に履歴を書き換えない限り)。
しかも、リポジトリが既に clone されたり fork されたりしていた場合、自分のリポジトリで履歴を消しても、他の場所に残ったままになることもあり得ます。だから「漏れたファイルを消す」よりも、「漏れた瞬間に鍵を無効化する」方が先決になります。
CTF 後に調べた対策
このステージをきっかけに、Git のシークレット混入対策を改めて調べました。
最も基本的なのは、コミットされる前に検出する仕組みです。git-secrets(AWS Labs 製)は AWS のキーパターンに特化していて、git commit 時にフックでブロックしてくれます。より汎用的なものとして gitleaks(公式)や trufflehog(公式)があり、こちらは AWS だけでなく多くのサービスのキーパターンを検出可能です。trufflehog は検出したキーを実際に API で叩いて「生きているか」まで確認できる、というのが面白い特徴でした。
現在の本命は、GitHub のシークレットスキャン + プッシュ保護(GitHub 公式ドキュメント)です。GitHub 側で 200 種類以上のシークレット形式を自動検出し、シークレットを含む push をそもそもブロックしてくれます。パブリックリポジトリなら無料、プライベートは GitHub Advanced Security が必要ですが、「pre-commit を導入する」よりも「GitHub の機能を有効化する」方が、組織全体への展開ハードルは低そうです。
そして、もし既に漏らしてしまった場合の手順もはっきりしています。まず鍵を即座にローテーションして(履歴削除より先)、そのうえで git filter-repo などのツールで履歴を書き換える。ただ、clone や fork されている前提なら、結局のところローテーションがすべてです。
実務で意識しておきたいこと
これは意外と起こりやすいミスです。.env を .gitignore で外していても、それを追加する前に一度コミットしてしまっていれば、履歴には残ってしまう。誰にでも起こりうるからこそ、人の注意力に頼るのではなく、仕組みで防ぐことが大事だと実感しました。
GitHub のプッシュ保護を有効にする、過去の履歴を定期的にスキャンする。こうした仕組みを入れておくと、「うっかり」が事故になる前に止められます。
✅ この章のポイント
- Git は「削除コミット」では履歴上のファイルを消せない
- 漏れた時の対応は「履歴削除より先に鍵のローテーション」が鉄則
- 検出は pre-commit(gitleaks 等)と GitHub のプッシュ保護の二段構え
Dockerレイヤー ── 「rm したから消えた」の落とし穴
DataAnalystRoleでECRリポジトリが見えることに気がついた。 Dockerイメージのビルド履歴にはかつて含まれていた機密情報が残ることがある。 イメージのレイヤーを深掘りしてみよう。
RUN rm の後ろにファイルが残っていた
ECR のイメージのビルド履歴を確認すると、COPY secret.txt . の次の行に RUN rm secret.txt が並んでいるのが見えました。最初は削除しているのだから、もう取れないかなと思ったのですが、過去のレイヤーを見ていくと、その secret.txt がそのまま残っていました。
私は普段の業務でも Docker を使っていますが、イメージのレイヤーを一枚ずつ覗くような操作は初めてでした。イメージのレイヤー構成(manifest)や、各レイヤーの識別子(digest)の取り方を調べながら、手探りで掘り進めていく。普段は「ビルドして動かす」ことしかしていなかった自分にとって、イメージの中がこんな風に開けるとは、正直思っていませんでした。
なぜこれが成立したのか
Docker のイメージは追記専用のレイヤー構造でできています。COPY でファイルを追加するレイヤーも、RUN rm でファイルを削除するレイヤーも、どちらも「新しいレイヤーを上に積み増す」操作であって、過去のレイヤーは変更されません。最終的なコンテナの中ではファイルが見えなくなっていても、過去のレイヤーを直接取り出せば、削除前のファイルがそのまま出てきます。
つまり Dockerfile に COPY secret.txt . && RUN rm secret.txt と書いて「使ったから消した」つもりでも、それは表面上の話。イメージを pull できる人なら、誰でも復元できてしまいます。Git の履歴と発想が似ていますね。
CTF 後に調べた対策
このステージをきっかけに Docker のシークレット管理について調べてみると、普段の使い方では触れない仕組みがいくつも出てきました。
最も根本的な対策は BuildKit Secret Mount(公式ドキュメント)でした。RUN --mount=type=secret,id=mysecret ... という書き方で、ビルド時にシークレットをマウントだけして、レイヤーには一切残しません。COPY で持ち込んで RUN rm するという発想そのものを不要にする仕組みです。「使ったから消す」のではなく「最初からレイヤーに残さない」という考え方です。
併せて組み合わせるべきなのが .dockerignore(公式)です。.gitignore の Docker 版で、ビルドコンテキストから特定のファイルを除外します。.env や secrets/ を予め除外しておけば、雑に COPY . . と書いても機密ファイルが混入しません。
ほかにマルチステージビルドでビルド用と実行用のレイヤーを分ける手法もありますが、まずは上の2つで十分に効きそうです。
なお、ECR にはイメージスキャン機能(Basic / Enhanced)がありますが、これは主に CVE(脆弱性)を検出するためのもので、「レイヤーに残ったシークレット」を見つけるものではありません。スキャンを有効にしているからといって、レイヤーに残ったシークレットの問題が防げるわけではない、という点は気をつけたいです。
実務で意識しておきたいこと
Docker は普段から使っていましたが、BuildKit Secret Mount は今回初めて知りました。シークレットを「使ったら消す」のではなく「最初からレイヤーに残さない」という発想は、Dockerfile を書くときにぜひ意識しておきたいところです。
Git の履歴も、Docker のレイヤーも、構造が「追記」になっている以上、消したつもりのものが残るのは当然です。「消す」より「最初から持ち込まない」を前提に組み立てるのが安全だと感じました。
✅ この章のポイント
- Docker イメージは追記専用、
RUN rmしても過去レイヤーには残る - 根本対策は BuildKit Secret Mount で「レイヤーに残さない」設計
- ECR のイメージスキャンは CVE 検出用、シークレット検出は別問題
シークレット管理サービス ── 「暗号化してるから大丈夫」の落とし穴
DataAnalystRoleの権限でLambda関数が見えることに気がついた。 Lambda関数には「環境変数」という設定情報を埋め込む仕組みがある。 開発者がうっかり機密情報を環境変数に書いていることがある。確認してみよう。
Lambda環境変数に
/techvault/internal/api-keyというSSMのパスが書いてあった。 SSMパラメータストアはSecrets Managerに似た機密情報の管理サービスだ。 階層構造で管理されているので、パスを辿って掘り下げてみよう。
暗号化されているはずなのに、見えてしまった
Lambda 関数の環境変数を get-function-configuration で覗くと、そこには機密情報が普通に書かれていました。「環境変数だから設定の範囲」と思い込んでいた箇所に、しっかりとシークレットが置かれていたのです。
さらに、その環境変数の中に /techvault/internal/api-key という SSM のパスが書いてあったので、辿ってみました。SSM Parameter Store の SecureString は暗号化されているはずですが、--with-decryption を付けて呼び出すと、中身が見えてしまいました。
正直、私はそれまで「Secrets Manager や SecureString に入れておけば安心」と思っていた節が少しありました。でも実際には、権限さえ持っていれば、暗号化された値も容易に取得できてしまうのです。
なぜこれが成立したのか
「暗号化されている」と「安全に守られている」は別の話です。
SSM SecureString も Secrets Manager も、保管時の暗号化はしてくれます。誰かが直接ストレージから読んでも、暗号化されたバイト列しか見えない、という意味では確かに安全です。しかし、使用時(API 経由で取得するとき)は別の話。ssm:GetParameter と kms:Decrypt の権限を持っていれば、誰でも --with-decryption で中身を引き出せます。
つまり、「暗号化」は保管時の話、「アクセス制御」は使用時の話で、両方が揃って初めて安全と言えます。CTF では DataAnalystRole にたまたまその両方の権限が付いていたので、シークレットが容易に得られてしまったのです。また Lambda の環境変数に至っては暗号化すらされておらず、get-function-configuration の権限があれば誰でも平文で読める状態でした。
CTF 後に調べた対策
このステージで認識が崩れた部分があったので、対策を改めて調べました。
まず大前提として、最小権限の原則(公式のベストプラクティス)が出発点になります。ssm:GetParameter や secretsmanager:GetSecretValue の権限を Resource: "*" で付けていないか。SSM Parameter Store ならパス階層を活用して arn:aws:ssm:...:parameter/myapp/prod/* のように絞れますし、Secrets Manager もシークレット名 ARN で絞れます。
特に効くと感じたのが、Secrets Manager のリソースベースポリシーです。これはシークレット自身に「このシークレットは Role-A と Role-B しか読めません」と直接書けるポリシーで、IAM ポリシーが広くなってしまっていても、シークレット側で最終的にブロックできます。SSM Parameter Store にはこの機能がないので、Secrets Manager を選ぶ意味のひとつだと知りました。
もう一つ、KMS Key Policy での二重ロックも有効です。SecureString や Secrets Manager は内部的に KMS で暗号化されていますが、Customer Managed Key を使えば、KMS Key 側で「この鍵を使える Principal」を制限できます。ssm:GetParameter の権限を持っていても、KMS Decrypt の権限がなければ復号できない。こうして多層で防御を組めるわけです(公式)。
そして Lambda の環境変数。これはそもそも「設定値」を入れるための場所であって、シークレット保管庫ではない、という整理が大事でした。シークレットは Lambda Extensions の Parameters and Secrets Lambda 拡張を使って、実行時に Secrets Manager から取得するのが推奨されています。
実務で意識しておきたいこと
Secrets Manager や SecureString を使うとき、つい「暗号化して保存できている」ことで安心しがちです。でも実際に重要なのは、「誰がそのシークレットを読めるか」というアクセス制御の視点でした。
リソースベースポリシーや Customer Managed KMS Key を使えば、「このシークレットはこのロールしか読めない」と明示的に縛れます。「暗号化」と「アクセス制御」を別物として両方押さえる。これがこの章で一番腹落ちした視点でした。
✅ この章のポイント
- 「暗号化」は保管時の話、「アクセス制御」は使用時の話、両方必要
- Secrets Manager のリソースベースポリシーで「誰が読めるか」を明示
- Lambda の環境変数はシークレット保管庫ではなく、実行時取得が推奨
ランタイム ── ファイルになくても、サーバーから漏れる
TechVault Portalの
/dashboardでは、ダッシュボード告知に外部リンクを貼ると、リンク先の内容を読み取ってカードを自動生成する。 先のステージで見つけたinternal-data-serverはブラウザから直接開けないはずだが、告知カード生成処理は社内ネットワーク側からリンク先を確認している。 SSRFという脆弱性を手がかりに、このプレビュー機能の挙動を調べ、内部APIの案内から次の入口を見つけて、一時認証情報にたどり着けるか確認しよう。
「IMDSv1 がNG」の本当の意味を体感した
「IMDSv1 がセキュリティ的にNG」とは知っていたけれど、なぜNGなのかは、ちゃんと理解していなかったことに、今回攻撃をしてみて初めて気づきました。
ダッシュボードの「外部リンクをカードに自動生成する」機能から始まって、URL パラメータを書き換えていくと、社内ネットワーク内の API に到達し、最終的に `http://169.254.169.254/…`(EC2 のメタデータサービス)まで辿り着きました。そこから IAM ロールの一時認証情報を引き出せたとき、「これが IMDSv1 の脆弱性か」と納得できました。
なお、URL のチェーン構築には少し戸惑いましたが、AI に構成や状況を伝えたら数秒で組み立ててくれました。ここでも攻撃の組み立てそのもののハードルが下がっている、という気づきがありました(これは最後の章でもう少し触れます)。
なぜこれが成立したのか
EC2 のメタデータサービス(IMDS)は、インスタンスの中から `http://169.254.169.254/` にアクセスすると、自分自身の情報や IAM ロールの一時認証情報が取得できる仕組みです。アプリケーションが AWS API を呼び出すときに使う、便利な仕掛けです。
IMDSv1 は単純な GET リクエスト一発で情報が取れます。認証もトークンも不要。だからこそ、サーバー側で任意 URL にアクセスできる脆弱性(SSRF)があると、内部から IMDS を叩いて認証情報を引き出せてしまうわけです。これは 2019 年の Capital One 事件で大規模に悪用されたパターンで、AWS が後継の IMDSv2 を導入する直接の動機になりました。
ここで重要なのは、シークレットがファイルやコードのどこにも書かれていなくても、攻撃が成立してしまうという点です。これまでの章では「シークレットがどこかに残っている」話でしたが、このステージは「動いているサーバーそのものからシークレットが漏れる」。発想がひとつ別の次元にあります。
CTF 後に調べた対策
IMDSv1 を狙うこの攻撃に対しては、対策が比較的はっきりしています。
最も効くのが IMDSv2 の強制(公式ドキュメント)です。IMDSv2 はメタデータを取得する前に、まず PUT リクエストでセッショントークンを取得する仕組みになっていて、その上で GET 時にヘッダーでトークンを送る必要があります。SSRF の多くは GET しか発行できず、カスタムヘッダーも付けられないので、そもそも PUT が打てない → トークン取れない → メタデータも取れない、という設計で防げます。既存インスタンスは aws ec2 modify-instance-metadata-options --http-tokens required で IMDSv2 必須に切り替えできます。
新規インスタンスのために、アカウント全体のデフォルトを IMDSv2 必須にすることもできます(公式)。複数 AWS アカウントを運用している場合は、SCP(Service Control Policy)で組織レベルで IMDSv2 を強制するという選択肢もあります。
「いきなり IMDSv2 必須にすると、IMDSv1 を使っているアプリが壊れるのでは?」という不安には、CloudWatch の MetadataNoToken メトリクスが便利でした。これは「トークンなしで IMDS にアクセスされた回数」を計測するもので、ゼロが続いていれば IMDSv1 を無効化しても安全、と判断できます。
これらは「IMDS 側」の対策ですが、アプリ側の SSRF 対策(URL を扱う機能で内部 IP を拒否する、許可リスト方式にする等)と IAM ロールの権限最小化(漏れた場合の被害範囲を限定する)も組み合わせて、多層で守るのが大切です。
実務で意識しておきたいこと
EC2 を使うなら、IMDSv2 が強制になっているか、新しく作るインスタンスでデフォルト必須の設定が入っているか、Terraform の Launch Template に IMDSv2 必須の設定(metadata_options の http_tokens = "required")が書かれているか。このあたりは、設計やレビューの段階で押さえておきたいポイントだと感じました。
シークレットの管理を考えるとき、これまでの自分は「ファイルやコードにある何か」ばかりを思い浮かべていました。しかし動いているサーバーそのものから漏れる経路もある、と身に染みて学ぶことができました。
✅ この章のポイント
- IMDSv1 + SSRF は Capital One 事件の典型パターン、今もよくある
- IMDSv2 強制(HttpTokens=required)で大半の SSRF 経由攻撃を防げる
- シークレットは「ファイル」だけでなく「動作中のサーバー」からも漏れる
CTFと勉強を通じての所感
初参加でやり切れた、その達成感
CTF に参加するのは今回が初めてでした。「セキュリティ専門ではない自分が、果たしてどこまで解けるのか」という不安半分、好奇心半分での参戦でしたが、ところどころで Claude に力を借りつつ、制限時間を 10 分ほどオーバーしながらも、全問解くことができました。これは率直に嬉しかったです。
CTF が終わってからも、本記事で扱った 5 つの落とし穴を中心に、対策を調べていくうちに「攻撃を体験すると、防御の理解がここまで変わるのか」と何度も実感しました。コードや設定を「セキュリティ」の視点で読み直す癖がついた、これが今回の最大の収穫だと感じています。
ほかにも印象的だったステージ
本記事には収まりきらなかったのですが、特に印象的だったのが Bedrock Agent の権限を悪用するステージでした。
仕組み自体はシンプルで、エージェントは強い権限を持っていて、ユーザーから「これをやって」と呼び出されたら、その権限で AWS のリソースを操作してくれます。問題は、呼び出すユーザーに権限がなくても、エージェント側の権限で実行されてしまうという点です。このステージでは、自分(DataAnalystRole)では直接読めない S3 オブジェクトを、Bedrock Agent 経由で呼び出すことで引き出せてしまいました。
「権限のないユーザーが、強い権限を持つエージェントを踏み台にして情報を得る」。これは Confused Deputy 問題 と呼ばれる古典的な脆弱性パターンですが、AI エージェントが普及する中で新しいパターンとして覚えておかなくてはいけないと感じました。AI に権限を委ねる時、信頼境界をどこに引くか。これは今後ますます重要になるテーマだと思います。
AI と並走する、懐かしい感覚
最近の自分は、AI に指示を丸投げして、出てきた結果をレビュー・判断するのが中心になっていました。What を与えて、How は任せきり状態。それはそれで効率的ですし、生産性も上がっているはずなのですが、今回 CTF を解いている最中の感覚は、それとは少し違っていました。
AI に状況を伝えながら次の一手を相談し、疑問が生じたら聞いて即解消する。長時間ぶっ通しで考えながら手を動かす、いわゆるフローに近い感覚。What に対する How を、AI と一緒にひたすら模索する時間。ちょっと前まで普通だったその感覚が、少し懐かしく感じてしまったことには、自分でも驚きました。
CTF のような探索的なタスクは、AI に丸投げするより並走する方が合っているのかもしれません。これは今後の AI の使い方を考える上でも、ひとつの実感として残った気がします。
同時に感じた、危機感
その並走の楽しさと表裏一体で、強い危機感も覚えた CTF でした。
セキュリティ特化していない自分のようなエンジニアでも、AI の助けがあれば、時間さえかければ、かなり幅広い攻撃を組み立てられてしまう。SSRF の URL チェーンも、AI に状況を渡せば数秒で構築できました。攻撃の組み立てそのもののハードルが、急速に下がっている時代に入ったということだと思います。
これは「攻撃者が AI を使う」ことを覚悟して、防御側の基本対策を改めて徹底する必要がある、という話だと受け取りました。本記事で扱った 5 つの落とし穴は、どれも対策が明確に存在するものばかりです。「対策はあるけど徹底できていない」という状態が、AI 時代の攻撃者にとってはご馳走になりかねないな、と感じました。
初参加を終えて
達成感と危機感が混じり合った CTF でしたが、結局のところ、自分のように普段はセキュリティを専門にしていないエンジニアにとって、攻撃者視点で見るという経験は、明らかに学びの密度が高く感じられました。また機会があれば挑戦したいと思います。
おわりに
CTF を通じて学んだことを 5 つの章にまとめてきましたが、振り返ってみると、共通していたのは「当たり前だと思っていたことを、もう一度疑ってみる」という姿勢でした。
.gitignore で外しているから大丈夫。RUN rm で消したから大丈夫。Secrets Manager で暗号化しているから大丈夫。IMDSv1 がよくないことは知っている。どれも一見正しそうですが、攻撃者視点に立つと、思っていたほどには「大丈夫」ではなかったり、「知っている」のレベルが浅かったりすることに気づきました。
AI で誰もが攻撃者になり得る時代です。だからこそ、自分の「大丈夫」を一度疑ってみるところから始めようと思います。