A Terraform module that deploys a Slack notification bot for Google Cloud Privileged Access Manager (PAM) events. When users request, approve, deny, or withdraw privileged access grants, your team gets notified in Slack with rich formatted messages and direct links to the GCP Console.
GCP Audit Logs (PAM events)
↓
Organization Log Sink
↓
Cloud Pub/Sub Topic
↓
Cloud Function v2 (Python 3.12)
↓
Slack (channel + DMs)
The module creates an organization-level log sink that captures PAM audit log events and routes them to a Pub/Sub topic. A Cloud Function processes each event, enriches it with resource names and approver group information, and posts formatted messages to Slack.
| Event | Channel Message | DM to Requester |
|---|---|---|
| New request (pending approval) | Yes — mentions approver groups | No |
| Auto-approved | Yes | No |
| Approved | Yes | Yes |
| Denied | Yes | Yes |
| Withdrawn | Yes | No |
- GCP Organization with PAM enabled
- A GCP project to host the infrastructure
- Terraform >= 1.0
- A Slack bot with the following OAuth scopes:
chat:writeim:write(required for DMs to requesters on approval/denial)users:lookupByEmailusergroups:read
module "pam_slackbot" {
source = "github.com/cameronmills/gcp-pam-slackbot"
org_id = "123456789"
project_id = "my-central-project"
slack_bot_token = var.slack_bot_token
slack_channel = "#pam-notifications"
approver_slack_handle_map = {
"engineering@example.com" = "engineering-team"
"security@example.com" = "security-team"
}
}| Name | Description | Type | Required | Default |
|---|---|---|---|---|
org_id |
GCP Organization ID | string |
Yes | — |
project_id |
GCP Project ID to deploy resources into | string |
Yes | — |
slack_bot_token |
Slack bot OAuth token (xoxb-...) |
string |
Yes | — |
region |
Region for the Cloud Function | string |
No | us-central1 |
slack_channel |
Slack channel for notifications (e.g. #pam-notifications) |
string |
Yes | — |
approver_slack_handle_map |
Map of Google group emails to Slack user group handles | map(string) |
No | {} |
| Name | Description |
|---|---|
pubsub_topic |
Pub/Sub topic ID |
log_sink_name |
Organization log sink name |
log_sink_writer_identity |
Writer service account for the log sink |
function_name |
Cloud Function name |
function_uri |
Cloud Function URL |
terraform init
terraform plan
terraform applyThe module provisions all required infrastructure, including:
- Cloud Function v2 — processes PAM events (Python 3.12, 256 MB, up to 10 instances)
- Organization Log Sink — routes PAM audit logs org-wide to Pub/Sub
- Cloud Pub/Sub Topic — receives and buffers events
- Secret Manager Secret — stores the Slack bot token
- Service Account + Custom IAM Role — least-privilege access to Resource Manager and PAM APIs
The following APIs must be enabled in your project:
cloudfunctions.googleapis.comcloudbuild.googleapis.compubsub.googleapis.comlogging.googleapis.comsecretmanager.googleapis.comrun.googleapis.comprivilegedaccessmanager.googleapis.com
- Go to api.slack.com/apps and create a new app
- Under OAuth & Permissions, add the scopes:
chat:write,im:write,users:lookupByEmail,usergroups:read - Install the app to your workspace and copy the Bot User OAuth Token (
xoxb-...) - Invite the bot to your notification channel
The approver_slack_handle_map variable maps Google group emails (configured as PAM approvers) to Slack user group handles. When a new access request is created, the bot mentions the relevant Slack group so approvers are notified.
approver_slack_handle_map = {
"engineering@example.com" = "engineering-team" # @engineering-team in Slack
"security@example.com" = "security-team" # @security-team in Slack
}This project uses Conventional Commits and release-please for automated changelog generation and versioning. Please follow the commit message format:
<type>: <description>
# Examples:
feat: add support for folder-scoped entitlements
fix: handle missing justification field gracefully
docs: update approver group mapping example
Common types: feat, fix, docs, refactor, chore. A feat commit bumps the minor version; a fix commit bumps the patch version. Breaking changes should include BREAKING CHANGE: in the commit body.
# Check Cloud Function logs
gcloud functions logs read pam-slack-notifier --project=YOUR_PROJECT_ID --limit=50
# List Pub/Sub topics
gcloud pubsub topics list --project=YOUR_PROJECT_ID
# List organization log sinks
gcloud logging sinks list --organization=YOUR_ORG_ID