【50種類以上のクラウドサービスに対応】GitHub のセキュリティ機能 Secret Scanning を実際にキーを流出させて試してみた

1分でアラート通知、5分で弊社オペレーションチームからの連絡が来ました
2021.07.22

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、GitHubのセキュリティ機能Secret Scanningを実際にAWSアクセスキーを流出させて試してみました。

Secret Scanningとは

GitHubのSecret Scanningは、GitHub上のリポジトリへのシークレットのコミットを検知し、アラート通知を行うセキュリティ機能です。

この機能はパブリックリポジトリ向けには既に提供がありましたが、今年4月にプライベートリポジトリ向けにも提供が開始されました。

シークレットの検知対象となるサービスはGitHubだけでなく、GitHubとシークレットスキャンパートナープログラムを結んでいる外部のサービスも対象となります。

Secret Scanningの仕組み

Secret Scanningは下記のような仕組みにより、外部のサービスプロバイダーと連携してシークレットの検知を行っています。

  1. ユーザーがGitHubリポジトリにシークレットをコミットまたはプッシュ
  2. GitHubがリポジトリをスキャンして既知のパターンのシークレット文字列を検索
  3. パターンに合致した場合はサービスプロバイダーのVerify Endpointに送信
  4. サービスプロバイダーは実際のシークレットと照合を行い、一致すれば無効化やアラート通知を行う

Secret scanning partner program - GitHub Docs より引用

外部サービスのシークレットの場合はGitHubでなく外部サービスが直接ユーザーへアラート通知を行います。

Secret Scanningを利用できるアカウント

ユーザー、組織(Organization)アカウントともに利用可能ですが、利用できるリポジトリ種類が異なります。

Organizationアカウントの場合は、FreeとTeamプランはパブリックリポジトリのみです。EnterPriseであればAdvanced Security機能を利用してプライベートリポジトリにも対応させられます。

ユーザーアカウントの場合は、FreeとProプランいずれもパブリックリポジトリのみ対応です。

パートナープログラム対象サービス(2021/7現在)

下記はプライベートリポジトリのシークレットスキャニングパートナープログラムの対象サービスです。2021/7現在で50以上のクラウドサービスが対象となっています。(リポジトリがパブリックかプライベートかで対象は異なります)

Partner Supported secret API slug
Adafruit IO Adafruit IO Key adafruit_io_key
Adobe Adobe Device Token adobe_device_token
Adobe Adobe Service Token adobe_service_token
Adobe Adobe Short-Lived Access Token adobe_short_lived_access_token
Adobe Adobe JSON Web Token adobe_jwt
Alibaba Cloud Alibaba Cloud Access Key ID alibaba_cloud_access_key_id
Alibaba Cloud Alibaba Cloud Access Key Secret alibaba_cloud_access_key_secret
Amazon Web Services (AWS) Amazon AWS Access Key ID aws_access_key_id
Amazon Web Services (AWS) Amazon AWS Secret Access Key aws_secret_access_key
Asana Asana Personal Access Token asana_personal_access_token
Atlassian Atlassian API Token atlassian_api_token
Atlassian Atlassian JSON Web Token atlassian_jwt
Atlassian Bitbucket Server Personal Access Token bitbucket_server_personal_access_token
Azure Azure DevOps Personal Access Token azure_devops_personal_access_token
Azure Azure SAS Token azure_sas_token
Azure Azure Service Management Certificate azure_management_certificate
Azure Azure SQL Connection String azure_sql_connection_string
Azure Azure Storage Account Key azure_storage_account_key
Checkout.com Checkout.com Production Secret Key checkout_production_secret_key
Checkout.com Checkout.com Test Secret Key checkout_test_secret_key
Clojars Clojars Deploy Token clojars_deploy_token
CloudBees CodeShip CloudBees CodeShip Credential codeship_credential
Databricks Databricks Access Token databricks_access_token
Discord Discord Bot Token discord_bot_token
Doppler Doppler Personal Token doppler_personal_token
Doppler Doppler Service Token doppler_service_token
Doppler Doppler CLI Token doppler_cli_token
Doppler Doppler SCIM Token doppler_scim_token
Dropbox Dropbox Access Token dropbox_access_token
Dropbox Dropbox Short Lived Access Token dropbox_short_lived_access_token
Dynatrace Dynatrace Access Token dynatrace_access_token
Dynatrace Dynatrace Internal Token dynatrace_internal_token
EasyPost EasyPost Production API Key easypost_production_api_key
EasyPost EasyPost Test API Key easypost_test_api_key
Facebook Facebook Access Token facebook_access_token
Fastly Fastly API Token fastly_api_token
Finicity Finicity App Key finicity_app_key
Flutterwave Flutterwave Live API Secret Key flutterwave_live_api_secret_key
Flutterwave Flutterwave Test API Secret Key flutterwave_test_api_secret_key
Frame.io Frame.io JSON Web Token frameio_jwt
Frame.io Frame.io Developer Token frameio_developer_token
GitHub GitHub Personal Access Token github_personal_access_token
GitHub GitHub OAuth Access Token github_oauth_access_token
GitHub GitHub Refresh Token github_refresh_token
GitHub GitHub App Installation Access Token github_app_installation_access_token
GitHub GitHub SSH Private Key github_ssh_private_key
GoCardless GoCardless Live Access Token gocardless_live_access_token
GoCardless GoCardless Sandbox Access Token gocardless_sandbox_access_token
Google Cloud Google API Key google_api_key
Google Cloud Google Cloud Private Key ID google_cloud_private_key_id
Grafana Grafana API Key grafana_api_key
Hashicorp Terraform Terraform Cloud / Enterprise API Token terraform_api_token
Hubspot Hubspot API Key hubspot_api_key
Intercom Intercom Access Token intercom_access_token
Ionic Ionic Personal Access Token ionic_personal_access_token
Ionic Ionic Refresh Token ionic_refresh_token
Linear Linear API Key linear_api_key
Linear Linear OAuth Access Token linear_oauth_access_token
Lob Lob Live API Key lob_live_api_key
Lob Lob Test API Key lob_test_api_key
Mailchimp Mailchimp API Key mailchimp_api_key
Mailgun Mailgun API Key mailgun_api_key
MessageBird MessageBird API Key messagebird_api_key
npm npm Access Token npm_access_token
NuGet NuGet API Key nuget_api_key
Onfido Onfido Live API Token onfido_live_api_token
Onfido Onfido Sandbox API Token onfido_sandbox_api_token
OpenAI OpenAI API Key openai_api_key
Palantir Palantir JSON Web Token palantir_jwt
Postman Postman API Key postman_api_key
Proctorio Proctorio Consumer Key proctorio_consumer_key
Proctorio Proctorio Linkage Key proctorio_linkage_key
Proctorio Proctorio Registration Key proctorio_registration_key
Proctorio Proctorio Secret Key proctorio_secret_key
Pulumi Pulumi Access Token pulumi_access_token
PyPI PyPI API Token pypi_api_token
RubyGems RubyGems API Key rubygems_api_key
Samsara Samsara API Token samsara_api_token
Samsara Samsara OAuth Access Token samsara_oauth_access_token
SendGrid SendGrid API Key sendgrid_api_key
Shippo Shippo Live API Token shippo_live_api_token
Shippo Shippo Test API Token shippo_test_api_token
Shopify Shopify App Shared Secret shopify_app_shared_secret
Shopify Shopify Access Token shopify_access_token
Shopify Shopify Custom App Access Token shopify_custom_app_access_token
Shopify Shopify Private App Password shopify_private_app_password
Slack Slack API Token slack_api_token
Slack Slack Incoming Webhook URL slack_incoming_webhook_url
Slack Slack Workflow Webhook URL slack_workflow_webhook_url
SSLMate SSLMate API Key sslmate_api_key
SSLMate SSLMate Cluster Secret sslmate_cluster_secret
Stripe Stripe API Key stripe_api_key
Stripe Stripe Live API Secret Key stripe_live_secret_key
Stripe Stripe Test API Secret Key stripe_test_secret_key
Stripe Stripe Live API Restricted Key stripe_live_restricted_key
Stripe Stripe Test API Restricted Key stripe_test_restricted_key
Stripe Stripe Webhook Signing Secret stripe_webhook_signing_secret
Tableau Tableau Personal Access Token tableau_personal_access_token
Telegram Telegram Bot Token telegram_bot_token
Tencent Cloud Tencent Cloud Secret ID tencent_cloud_secret_id
Twilio Twilio Account String Identifier twilio_account_sid
Twilio Twilio API Key twilio_api_key

実際にシークレットを流出させてみる

実際にSecret Scanningの動作を試してみます。個人のGitHubユーザーアカウントのパブリックリポジトリで、AWSのIAMアクセスキーを流出させてみます。

IAMユーザーを作成してアクセスキーを発行します。念のため権限は何も付与していません。

パブリックリポジトリに発行したIAMアクセスキーを記載してコミットします。

するとAWSからものの1分でアラート通知のメールが送付されてきました。GitHubアカウントのどのファイルで流出したかまで教えてくれています。

Case ID: XXXXXXXXXXXX
Subject: ACTION REQUIRED: Your AWS Access Key is Exposed for AWS Account XXXXXXXXXXX
Severity: Urgent
Correspondence: Hello,

We have become aware that the AWS Access Key AKIXXXXXXXXXXXX , belonging to IAM User MySecretScanningTestUser , along with the corresponding Secret Key is publicly available online at https://github.com/cm-rwakatsuki/public_test/blob/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/README.md.

検証後は安全のためリポジトリはプライベート化し、IAMアクセスキーは削除しました。

余談

余談というよりは本ブログの本編です。

今回の検証を行ったAWSアカウントは弊社のクラスメソッドメンバーズから払い出されたアカウントであったため、キーを流出させてから5分後にメンバーズの弊社オペレーションチームから社内のSlackで確認の連絡が私へきました。お騒がせして本当に申し訳ないです…すみません、連休中の夜分遅くに本当にすみません…

タイムラインとしては以下のようになります。

22:25 キーをパブリックリポジトリにコミットする
22:26 AWSからキー流出のアラート通知がメールで来る
22:27 弊社オペレーションチームからキー流出の連絡がメールで来る
22:30 社内Slackでオペレーションチームから確認連絡が来る

Secret Scanningもですが、クラスメソッドメンバーズ(↓下の方にバナーも出ていると思います)のオペレーションチームのスピード感もすごいです。弊社の主力サービスはこんな優秀な人たちの24/365のオペレーションよって支えられているのだなと改めて実感しました。

以上