identity-access-management について
スタートアップ向けのID・アクセス管理スキルです。Google Workspace、Okta、Azure AD(Entra ID)でのSSO、プロビジョニング、MFA、アクセスガバナンスを、CLIやAPIの例とともに扱います。
主な機能
- 01SAMLとOIDCによるSSO設定
- 02SCIMユーザープロビジョニング
- 03MFAポリシー設定
- 04グループベースのアクセス制御
- 05監査ログとアクセスレビュー
- 06退職者のアクセス停止手順
活用シーン
- 01アプリ認証の一元化
- 02コンプライアンス用アクセス証跡の準備
- 03従業員の入退社手続きの自動化
- 04インシデント時のアクセス権取り消し
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill identity-access-managementインストール後、Claude Code で/identity-access-managementを入力して読み込まれたか確認します。
詳細
スタートアップ向け ID・アクセス管理
チームが数人を超えたら、ID 管理の一元化は任意ではありません。このスキルでは、スタートアップで最もよく使われている 3 つの ID プロバイダーである Google Workspace、Okta、Azure AD(Entra ID)を使った、SSO、SCIM プロビジョニング、MFA の強制、アクセスガバナンスの実用的で本番環境向けの設定を紹介します。
1. このスキルを使うタイミング
次のような場合に、このスキルを活用してください。
- 初めての SSO 設定 -- アプリごとの個別ログインから、一元化された認証に移行するとき。
- コンプライアンス監査の準備 -- SOC 2、ISO 27001、または HIPAA で、アクセス制御、MFA の強制、監査ログの文書化が必要なとき。
- チームの成長期 -- 従業員数が 15~20 人に達し、手動でのオンボーディング/オフボーディングでミスが増えてきたとき。
- ベンダーのセキュリティ質問票への対応 -- 顧客から ID 管理体制について質問され、管理策を示す必要があるとき。
- インシデント対応 -- 退職者や侵害されたユーザーのアクセスを、すべてのシステムで迅速に取り消す必要があるとき。
対応が遅れている兆候:
- スプレッドシートやチャットチャンネルでパスワードを共有している。
- 誰がいつ何にアクセスしたかを記録する一元的な監査ログがない。
- オフボーディングに 1 営業日以上かかる。
- 開発者が本番環境への管理者アクセスを常時保持している。
2. ID プロバイダーとしての Google Workspace
Google Workspace は、スタートアップで最も一般的な IdP の出発点です。GAM CLI ツールと組み合わせることで、強力な自動化を実現できます。
GAM(Google Apps Manager)のインストール
# Install GAM on Linux/macOS
bash <(curl -s -S -L https://gam-shortn.appspot.com/gam-install)
# Authorize GAM with your Workspace domain
gam oauth create
# Verify connection
gam info domain
組織部門の作成
組織部門(OU)で、ポリシーの継承とアプリへのアクセスを制御します。
# Create OUs for team structure
gam create org "Engineering"
gam create org "Engineering/Backend"
gam create org "Engineering/Frontend"
gam create org "Operations"
gam create org "Operations/IT"
gam create org "Finance"
gam create org "Contractors"
# Move a user into an OU
gam update user [email protected] org "Engineering/Backend"
# List all OUs
gam print orgs
Google Workspace での SAML アプリの設定
# Export the Google IdP metadata (download from Admin Console or use GAM)
# Admin Console: Apps > Web and mobile apps > Add app > Search for app > Download IdP metadata
# For a custom SAML app, you need:
# 1. ACS URL (from the service provider)
# 2. Entity ID (from the service provider)
# 3. Name ID format (usually EMAIL)
# Example: Add a custom SAML app via Admin Console API
gam create samlapp "Internal Dashboard" \
acs_url "https://dashboard.company.com/saml/acs" \
entity_id "https://dashboard.company.com" \
name_id_format "EMAIL" \
name_id "user.primaryEmail"
# Assign the app to an OU
gam update samlapp "Internal Dashboard" org "Engineering" enabled on
# Verify SAML app status
gam print samlappinfo "Internal Dashboard"
Google Workspace での SCIM プロビジョニング
# Enable auto-provisioning for supported apps
# Google Workspace supports automatic user provisioning for apps like:
# Slack, Zoom, Box, Dropbox, Asana, GitHub Enterprise
# List provisioned apps
gam print tokens
# Force sync provisioning for an app
gam sync samlapp "Slack" users
# Bulk create users from CSV
# users.csv format: firstname,lastname,email,org,password
gam csv users.csv gam create user ~email \
firstname ~firstname lastname ~lastname \
password ~password org ~org \
changepassword on
Workspace レベルでの MFA の強制
# Enforce 2-step verification for the entire domain
gam update org "/" 2sv enforced
# Enforce 2SV for a specific OU
gam update org "Engineering" 2sv enforced
# Set enforcement date (give users time to enroll)
gam update org "/" 2sv enforced enforceddate 2026-04-15
# Check 2SV enrollment status for all users
gam print users fields isEnforcedIn2Sv,isEnrolledIn2Sv
# Find users who have NOT enrolled in 2SV
gam print users query "isEnrolledIn2Sv=false" fields primaryEmail,name
3. Okta の設定
Okta はスタートアップ向けの無料プラン(Okta for Startups プログラム -- 最大 100 ユーザー)を提供しており、専用の IdP が必要なチームに最適です。
API を使用した Okta の初期設定
# Set your Okta domain and API token
export OKTA_ORG_URL="https://company.okta.com"
export OKTA_API_TOKEN="your-api-token"
# Verify connectivity
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/org" | jq '.companyName'
# Create a user
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/users?activate=true" \
-d '{
"profile": {
"firstName": "Alice",
"lastName": "Engineer",
"email": "[email protected]",
"login": "[email protected]"
},
"credentials": {
"password": { "value": "TempP@ss123!" }
}
}' | jq '.id'
RBAC 用グループの作成
# Create groups
for group in "Engineering" "Operations" "Finance" "Contractors" "AdminAccess"; do
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/groups" \
-d "{\"profile\": {\"name\": \"${group}\", \"description\": \"${group} team group\"}}" \
| jq '{id: .id, name: .profile.name}'
done
# Add user to group
USER_ID="00u1abc123"
GROUP_ID="00g1def456"
curl -s -X PUT \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/groups/${GROUP_ID}/users/${USER_ID}"
Okta への SAML アプリケーションの追加
# Create a SAML 2.0 application
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/apps" \
-d '{
"name": "custom_saml_app",
"label": "Internal Dashboard",
"signOnMode": "SAML_2_0",
"settings": {
"signOn": {
"defaultRelayState": "",
"ssoAcsUrl": "https://dashboard.company.com/saml/acs",
"audience": "https://dashboard.company.com",
"recipient": "https://dashboard.company.com/saml/acs",
"destination": "https://dashboard.company.com/saml/acs",
"subjectNameIdFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
"attributeStatements": [
{
"type": "EXPRESSION",
"name": "email",
"namespace": "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
"values": ["user.email"]
},
{
"type": "EXPRESSION",
"name": "groups",
"namespace": "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
"values": ["getFilteredGroups({\"00g1def456\"}, \"group.name\", 50)"]
}
]
}
}
}' | jq '{id: .id, label: .label, status: .status}'
# Assign group to application
APP_ID="0oa1xyz789"
curl -s -X PUT \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/apps/${APP_ID}/groups/${GROUP_ID}"
Okta の MFA ポリシー
# Create an MFA enrollment policy requiring WebAuthn + TOTP
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/policies" \
-d '{
"type": "MFA_ENROLL",
"name": "Require Strong MFA",
"status": "ACTIVE",
"settings": {
"factors": {
"webauthn": { "enroll": { "self": "REQUIRED" } },
"google_otp": { "enroll": { "self": "OPTIONAL" } },
"okta_email": { "enroll": { "self": "NOT_ALLOWED" } },
"okta_sms": { "enroll": { "self": "NOT_ALLOWED" } }
}
}
}' | jq '{id: .id, name: .name, status: .status}'
4. Azure AD/Entra ID
Azure AD(現在の Microsoft Entra ID)は、Microsoft 365 または Azure クラウドを使用するスタートアップでよく使われています。
Azure CLI の設定
# Install Azure CLI and sign in
az login
# Set the default tenant
az account set --subscription "your-subscription-id"
# Verify tenant
az ad signed-in-user show --query '{name:displayName, email:userPrincipalName}'
ユーザーとグループの作成
# Create a user
az ad user create \
--display-name "Alice Engineer" \
--user-principal-name "[email protected]" \
--password "TempP@ss123!" \
--force-change-password-next-sign-in true
# Create security groups
for group in "SG-Engineering" "SG-Operations" "SG-Finance" "SG-Admins"; do
az ad group create --display-name "$group" --mail-nickname "$group"
done
# Add user to group
USER_OID=$(az ad user show --id "[email protected]" --query id -o tsv)
GROUP_OID=$(az ad group show --group "SG-Engineering" --query id -o tsv)
az ad group member add --group "$GROUP_OID" --member-id "$USER_OID"
# List group members
az ad group member list --group "SG-Engineering" --query '[].{name:displayName, email:userPrincipalName}' -o table
Graph API を使用した条件付きアクセス ポリシー
# Require MFA for all users accessing cloud apps
# Uses Microsoft Graph API
ACCESS_TOKEN=$(az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv)
curl -s -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
"https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
-d '{
"displayName": "Require MFA for all users",
"state": "enabledForReportingButNotEnforced",
"conditions": {
"users": {
"includeUsers": ["All"],
"excludeGroups": ["'${BREAKGLASS_GROUP_OID}'"]
},
"applications": {
"includeApplications": ["All"]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": ["mfa"]
}
}'
# Block legacy authentication (critical for security)
curl -s -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
"https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
-d '{
"displayName": "Block legacy authentication",
"state": "enabled",
"conditions": {
"users": { "includeUsers": ["All"] },
"applications": { "includeApplications": ["All"] },
"clientAppTypes": ["exchangeActiveSync", "other"]
},
"grantControls": {
"operator": "OR",
"builtInControls": ["block"]
}
}'
5. SSO 統合パターン
SAML と OIDC の選択ガイド
| 要素 | SAML 2.0 | OIDC/OAuth 2.0 |
|---|---|---|
| 最適な用途 | エンタープライズ向け SaaS アプリ | SPA、モバイルアプリ、API |
| トークン形式 | XML アサーション | JWT トークン |
| 設定の複雑さ | 高い(証明書、メタデータ XML) | 低い(クライアント ID +シークレット) |
| ログアウト | 一貫性がない(SLO のサポートは不十分) | トークンの有効期限切れ+取り消し |
| 使用する場面 | アプリが SAML のみをサポートしている場合 | 選択肢がある場合、または API 認証が必要な場合 |
経験則:SaaS ベンダーが OIDC をサポートしている場合は、OIDC を優先してください。SAML のみをサポートしている場合は、SAML を使用してください。インターネット経由で LDAP を使用することは決して避けてください。
よく使われる SaaS アプリの統合
Slack Enterprise SSO
# Okta OIDC integration for Slack
# 1. In Okta: Applications > Browse App Catalog > Slack
# 2. Configure with your Slack workspace URL
# 3. Enable SCIM provisioning
# Verify Slack SCIM connection
curl -s -H "Authorization: Bearer ${SLACK_SCIM_TOKEN}" \
"https://api.slack.com/scim/v2/Users?count=5" | jq '.Resources[].userName'
GitHub Organization SSO
# Configure SAML for GitHub Org (requires GitHub Enterprise Cloud)
# 1. GitHub Org Settings > Authentication security > Enable SAML
# 2. Provide IdP SSO URL, IdP issuer, public certificate from your IdP
# Use GitHub CLI to verify SSO status
gh api orgs/company/credential-authorizations --paginate \
| jq '.[] | {login: .login, credential_type: .credential_type, authorized_at: .authorized_credential_note}'
# Require SAML SSO for all org members
gh api -X PATCH orgs/company \
-f saml_enforced=true
AWS SSO(IAM Identity Center)
# Configure AWS IAM Identity Center with external IdP
aws sso-admin list-instances --query 'Instances[0].InstanceArn' --output text
INSTANCE_ARN="arn:aws:sso:::instance/ssoins-1234567890"
IDENTITY_STORE_ID="d-1234567890"
# Create a permission set
aws sso-admin create-permission-set \
--instance-arn "$INSTANCE_ARN" \
--name "DeveloperAccess" \
--description "Read-only + deploy access for engineers" \
--session-duration "PT8H"
# Attach AWS managed policy to permission set
PERMISSION_SET_ARN="arn:aws:sso:::permissionSet/ssoins-1234567890/ps-abc123"
aws sso-admin attach-managed-policy-to-permission-set \
--instance-arn "$INSTANCE_ARN" \
--permission-set-arn "$PERMISSION_SET_ARN" \
--managed-policy-arn "arn:aws:iam::aws:policy/ReadOnlyAccess"
# Assign group to AWS account with permission set
aws sso-admin create-account-assignment \
--instance-arn "$INSTANCE_ARN" \
--target-id "123456789012" \
--target-type AWS_ACCOUNT \
--permission-set-arn "$PERMISSION_SET_ARN" \
--principal-type GROUP \
--principal-id "a1b2c3d4-5678-90ab-cdef-GROUP001"
6. SCIM プロビジョニング
SCIM(System for Cross-domain Identity Management)は、SaaS アプリ全体でユーザーのライフサイクルを自動化します。
SCIM API の例
# Standard SCIM 2.0 endpoints (most IdPs and SaaS apps follow this)
SCIM_BASE="https://app.example.com/scim/v2"
SCIM_TOKEN="your-scim-bearer-token"
# List users
curl -s -H "Authorization: Bearer ${SCIM_TOKEN}" \
"${SCIM_BASE}/Users?count=10&startIndex=1" | jq '.Resources[] | {id, userName, active}'
# Create a user via SCIM
curl -s -X POST \
-H "Authorization: Bearer ${SCIM_TOKEN}" \
-H "Content-Type: application/scim+json" \
"${SCIM_BASE}/Users" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "[email protected]",
"name": { "givenName": "Alice", "familyName": "Engineer" },
"emails": [{ "primary": true, "value": "[email protected]", "type": "work" }],
"active": true,
"groups": []
}' | jq '{id, userName, active}'
# Deactivate a user via SCIM (PATCH is the standard for partial updates)
USER_SCIM_ID="abc-123-def"
curl -s -X PATCH \
-H "Authorization: Bearer ${SCIM_TOKEN}" \
-H "Content-Type: application/scim+json" \
"${SCIM_BASE}/Users/${USER_SCIM_ID}" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{ "op": "replace", "value": { "active": false } }]
}' | jq '{id, userName, active}'
# Delete a user permanently via SCIM
curl -s -X DELETE \
-H "Authorization: Bearer ${SCIM_TOKEN}" \
"${SCIM_BASE}/Users/${USER_SCIM_ID}"
SCIM グループ管理
# Create a group via SCIM
curl -s -X POST \
-H "Authorization: Bearer ${SCIM_TOKEN}" \
-H "Content-Type: application/scim+json" \
"${SCIM_BASE}/Groups" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Engineering",
"members": [
{ "value": "user-id-001", "display": "[email protected]" },
{ "value": "user-id-002", "display": "[email protected]" }
]
}' | jq '{id, displayName}'
# Add a member to an existing group
GROUP_SCIM_ID="grp-456"
curl -s -X PATCH \
-H "Authorization: Bearer ${SCIM_TOKEN}" \
-H "Content-Type: application/scim+json" \
"${SCIM_BASE}/Groups/${GROUP_SCIM_ID}" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op": "add",
"path": "members",
"value": [{ "value": "user-id-003" }]
}]
}'
7. MFA の強制
WebAuthn/パスキー(最も強力)
WebAuthn(FIDO2)ハードウェアキーとパスキーはフィッシング耐性があり、主要な MFA 要素として使用するべきです。
# Okta: Enforce WebAuthn as primary factor
curl -s -X PUT \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/org/factors/webauthn" \
-d '{ "status": "ACTIVE" }'
# Google Workspace: Enforce security keys only (disable SMS/voice)
gam update org "/" 2sv enforced allowedmethods security_key
# Azure AD: Require phishing-resistant MFA via conditional access
# (use the Graph API conditional access endpoint with authenticationStrengths)
curl -s -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
"https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
-d '{
"displayName": "Require phishing-resistant MFA for admins",
"state": "enabled",
"conditions": {
"users": { "includeRoles": ["62e90394-69f5-4237-9190-012177145e10"] },
"applications": { "includeApplications": ["All"] }
},
"grantControls": {
"operator": "OR",
"authenticationStrength": {
"id": "00000000-0000-0000-0000-000000000004"
}
}
}'
TOTP バックアップの設定
# Generate backup codes for users (Okta)
USER_ID="00u1abc123"
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/factors" \
-d '{
"factorType": "token:software:totp",
"provider": "GOOGLE"
}' | jq '{id: .id, status: .status}'
MFA のバイパス手順(緊急時)
# Okta: Reset MFA for a locked-out user
USER_ID="00u1abc123"
# List enrolled factors
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/factors" | jq '.[].factorType'
# Delete a specific factor to allow re-enrollment
FACTOR_ID="fct1abc123"
curl -s -X DELETE \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/factors/${FACTOR_ID}"
# Google Workspace: Generate backup verification codes
gam user [email protected] update backupcodes
# Azure AD: Require re-registration of MFA methods
az rest --method DELETE \
--url "https://graph.microsoft.com/v1.0/users/${USER_OID}/authentication/phoneMethods/3179e48a-750b-4051-897c-87b9720928f7"
8. ロールベースのアクセス制御
グループベースのアクセスパターン
すべてのアプリケーションの権限をグループに割り当て、個々のユーザーに直接割り当てないでください。
# Naming convention: APP-ROLE
# Examples:
# aws-developer -> AWS ReadOnly + deploy
# aws-admin -> AWS AdministratorAccess
# github-engineer -> GitHub write access
# github-admin -> GitHub admin access
# slack-member -> Slack standard member
# pagerduty-oncall -> PagerDuty responder role
# Okta: Create group rules for automatic assignment based on department
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
-H "Content-Type: application/json" \
"${OKTA_ORG_URL}/api/v1/groups/rules" \
-d '{
"type": "group_rule",
"name": "Auto-assign engineers to GitHub",
"conditions": {
"expression": {
"value": "user.department == \"Engineering\"",
"type": "urn:okta:expression:1.0"
}
},
"actions": {
"assignUserToGroups": { "groupIds": ["GITHUB_ENGINEERS_GROUP_ID"] }
}
}'
Just-in-Time(JIT)アクセス
# AWS: Grant temporary elevated access using STS assume-role
# The user assumes a role that expires after a set duration
aws sts assume-role \
--role-arn "arn:aws:iam::123456789012:role/EmergencyAdmin" \
--role-session-name "alice-incident-2026-03-24" \
--duration-seconds 3600 \
| jq '{AccessKeyId: .Credentials.AccessKeyId, Expiration: .Credentials.Expiration}'
# Okta: Create a time-limited group membership (via API scheduled task)
# Add user to admin group
curl -s -X PUT \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/groups/${ADMIN_GROUP_ID}/users/${USER_ID}"
# Schedule removal after 4 hours (use a cron job or automation tool)
echo "0 */4 * * * curl -s -X DELETE -H 'Authorization: SSWS ${OKTA_API_TOKEN}' \
'${OKTA_ORG_URL}/api/v1/groups/${ADMIN_GROUP_ID}/users/${USER_ID}'" | crontab -
緊急用アカウント
# Create break-glass accounts that bypass SSO/MFA for emergency access
# These accounts must be:
# 1. Excluded from conditional access / MFA policies
# 2. Protected with extremely long passwords stored in a physical safe
# 3. Monitored with alerts on any usage
# Azure AD: Create break-glass account
az ad user create \
--display-name "Break Glass 1" \
--user-principal-name "[email protected]" \
--password "$(openssl rand -base64 48)" \
--force-change-password-next-sign-in false
# Assign Global Administrator role
az ad group member add --group "SG-BreakGlass" --member-id "$BREAKGLASS_OID"
# Set up alert on break-glass sign-in (Azure Monitor)
az monitor activity-log alert create \
--name "BreakGlass-SignIn-Alert" \
--resource-group "security-rg" \
--condition category=Administrative and [email protected] \
--action-group "/subscriptions/SUB_ID/resourceGroups/security-rg/providers/microsoft.insights/actionGroups/SecurityTeam"
9. 監査とコンプライアンス
ログイン監査ログ
# Google Workspace: Pull login audit logs
gam report login user all start "2026-03-01" end "2026-03-24" \
fields "actorEmail,ipAddress,loginType,isSecondFactor,isSuspicious"
# Okta: Query system log for authentication events
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/logs?filter=eventType+eq+\"user.session.start\"&since=2026-03-01T00:00:00Z&limit=100" \
| jq '.[] | {actor: .actor.displayName, time: .published, outcome: .outcome.result, ip: .client.ipAddress}'
# Azure AD: Pull sign-in logs via Graph API
curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=createdDateTime ge 2026-03-01T00:00:00Z&\$top=50" \
| jq '.value[] | {user: .userDisplayName, app: .appDisplayName, status: .status.errorCode, ip: .ipAddress, mfa: .mfaDetail}'
アクセスレビュー
# List all users and their group memberships for quarterly access review
# Google Workspace
gam print group-members fields email,role > /tmp/access-review-groups.csv
# Okta: Export all users with their app assignments
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users?limit=200" \
| jq -r '.[] | [.profile.email, .status, .lastLogin] | @csv' > /tmp/okta-users.csv
# For each user, list their app assignments
while IFS= read -r user_id; do
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${user_id}/appLinks" \
| jq -r '.[] | [.label, .linkUrl] | @csv'
done < /tmp/okta-user-ids.txt > /tmp/okta-access-review.csv
# Azure AD: List role assignments
az role assignment list --all --query '[].{principal:principalName, role:roleDefinitionName, scope:scope}' -o table
コンプライアンスレポート
# Count of users with/without MFA enrolled
# Google Workspace
echo "=== MFA Enrollment Report ==="
echo "Enrolled:"
gam print users fields isEnrolledIn2Sv | grep -c True
echo "Not enrolled:"
gam print users fields isEnrolledIn2Sv | grep -c False
# Okta: Users without any MFA factor
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users?filter=status+eq+\"ACTIVE\"&limit=200" \
| jq '[.[] | select(.credentials.provider.type != "SOCIAL") | .id] | length'
# Check for stale accounts (no login in 90 days)
NINETY_DAYS_AGO=$(date -d "-90 days" +%Y-%m-%dT00:00:00Z 2>/dev/null || date -v-90d +%Y-%m-%dT00:00:00Z)
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users?filter=lastLogin+lt+\"${NINETY_DAYS_AGO}\"&limit=200" \
| jq '.[] | {email: .profile.email, lastLogin: .lastLogin}'
10. オフボーディング
アカウント無効化チェックリスト
従業員が退職する際は、この手順を実行します。順序が重要です。まずセッションを取り消し、その後にアカウントを無効化します。
DEPARTING_USER="[email protected]"
# Step 1: Revoke all active sessions immediately
# Okta
USER_ID=$(curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${DEPARTING_USER}" | jq -r '.id')
curl -s -X DELETE \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/sessions"
# Google Workspace: Revoke tokens and sign out
gam user "${DEPARTING_USER}" signout
gam user "${DEPARTING_USER}" deprovision
# Azure AD: Revoke all refresh tokens
az ad user update --id "${DEPARTING_USER}" --account-enabled false
az rest --method POST \
--url "https://graph.microsoft.com/v1.0/users/${DEPARTING_USER}/revokeSignInSessions"
# Step 2: Deactivate the user account
# Okta
curl -s -X POST \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/lifecycle/deactivate"
# Google Workspace
gam update user "${DEPARTING_USER}" suspended on
# Step 3: Transfer data ownership
# Google Workspace: Transfer Drive files
gam user "${DEPARTING_USER}" transfer drive [email protected]
# Google Workspace: Transfer Calendar ownership
gam user "${DEPARTING_USER}" transfer calendar [email protected]
# Step 4: Remove from all groups (prevents future provisioning)
# Okta
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${USER_ID}/groups" \
| jq -r '.[].id' | while read gid; do
curl -s -X DELETE \
-H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/groups/${gid}/users/${USER_ID}"
done
# Step 5: Revoke app-specific tokens
# GitHub: Remove from org
gh api -X DELETE "orgs/company/members/${DEPARTING_USER}"
# Slack: Deactivate via SCIM
SLACK_USER_ID=$(curl -s -H "Authorization: Bearer ${SLACK_SCIM_TOKEN}" \
"https://api.slack.com/scim/v2/Users?filter=userName+eq+\"${DEPARTING_USER}\"" \
| jq -r '.Resources[0].id')
curl -s -X PATCH \
-H "Authorization: Bearer ${SLACK_SCIM_TOKEN}" \
-H "Content-Type: application/scim+json" \
"https://api.slack.com/scim/v2/Users/${SLACK_USER_ID}" \
-d '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","value":{"active":false}}]}'
# AWS: Remove SSO access
aws sso-admin delete-account-assignment \
--instance-arn "$INSTANCE_ARN" \
--target-id "123456789012" \
--target-type AWS_ACCOUNT \
--permission-set-arn "$PERMISSION_SET_ARN" \
--principal-type USER \
--principal-id "$AWS_SSO_USER_ID"
# Step 6: Document and log
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) | OFFBOARD | ${DEPARTING_USER} | all sessions revoked, account suspended, data transferred to [email protected]" >> /var/log/offboarding-audit.log
オフボーディング後の確認
DEPARTING_USER="[email protected]"
# Verify account is suspended/deactivated
echo "=== Offboarding Verification ==="
# Google Workspace
gam info user "${DEPARTING_USER}" fields suspended | grep -i "suspended: true" && echo "[OK] Google suspended" || echo "[FAIL] Google still active"
# Okta
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/users/${DEPARTING_USER}" \
| jq -r '.status' | grep -q "DEPROVISIONED" && echo "[OK] Okta deprovisioned" || echo "[FAIL] Okta still active"
# GitHub
gh api "orgs/company/members/${DEPARTING_USER}" 2>&1 | grep -q "404" && echo "[OK] GitHub removed" || echo "[FAIL] GitHub still member"
# Check for any remaining active sessions in audit logs
echo "=== Checking for post-offboard activity ==="
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"${OKTA_ORG_URL}/api/v1/logs?filter=actor.alternateId+eq+\"${DEPARTING_USER}\"&since=$(date -u +%Y-%m-%dT%H:%M:%SZ)&limit=10" \
| jq '.[] | {time: .published, event: .eventType, outcome: .outcome.result}'
クイックリファレンス
| タスク | Google Workspace | Okta | Azure AD |
|---|---|---|---|
| ユーザーを作成 | gam create user | POST /api/v1/users | az ad user create |
| ユーザーを一時停止 | gam update user suspended on | POST /lifecycle/deactivate | az ad user update --account-enabled false |
| MFA を強制 | gam update org 2sv enforced | MFA 登録ポリシー | 条件付きアクセス ポリシー |
| セッションを取り消し | gam user signout | DELETE /users/{id}/sessions | revokeSignInSessions |
| ログインを監査 | gam report login | GET /api/v1/logs | GET /auditLogs/signIns |
| SCIM プロビジョニング | 対応アプリでは標準搭載 | アプリ統合の SCIM タブ | エンタープライズアプリのプロビジョニング |