This is an automated email from the ASF dual-hosted git repository.
pabloem pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new ad39be0f58b Clarify service account key issue reports (#39894)
ad39be0f58b is described below
commit ad39be0f58b3030da2ea126e369bb96b78b472cf
Author: HansMarcus01 <[email protected]>
AuthorDate: Wed Aug 26 14:03:22 2026 -0600
Clarify service account key issue reports (#39894)
---
infra/enforcement/README.md | 4 ++--
infra/enforcement/account_keys.py | 9 +++++----
infra/enforcement/sending.py | 10 ++++++++--
infra/enforcement/test_sending.py | 6 +++---
4 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/infra/enforcement/README.md b/infra/enforcement/README.md
index b92e5f7e180..90fc7697475 100644
--- a/infra/enforcement/README.md
+++ b/infra/enforcement/README.md
@@ -138,7 +138,7 @@ The enforcement tools are consolidated into a single daily
workflow (`.github/wo
This unified workflow executes both security domains sequentially:
- **IAM Policy Enforcement:** Validates user bindings against the defined
policies.
-- **Unmanaged Keys Audit:** Detects rogue service account keys generated
outside the official rotation system.
+- **Unmanaged Keys Audit:** Detects rogue service account keys generated
outside the official rotation system and reports them to the
`[IAC_DRIFT_SA_KEY]` issue.
**Note**:
- **Manual trigger**: The workflow can also be triggered manually via
`workflow_dispatch`.
@@ -175,7 +175,7 @@ python account_keys.py --action generate
- **check**: Validates service account keys and their permissions against
defined policies and reports any differences (default behavior)
- **announce**: Creates or updates a GitHub issue and sends an email
notification when service account keys policies differ from the defined ones.
- For general configuration errors, it updates the main compliance issue.
- - **For unmanaged/rogue keys (Security Alerts)**, it consolidates alerts
into a dedicated `[SECURITY]` issue acting as a live dashboard. It updates the
issue by placing the newest audit report at the top and moving the previous
reports into a collapsed `<details>` history section. If the keys are revoked
and the infrastructure becomes healthy, the system automatically resolves and
closes the issue.
+ - **For unmanaged/rogue keys**, it consolidates alerts into a dedicated
`[IAC_DRIFT_SA_KEY]` issue acting as a live dashboard. It updates the issue by
placing the newest audit report at the top and moving the previous reports into
a collapsed `<details>` history section. If the keys are revoked and the
infrastructure becomes healthy, the system automatically resolves and closes
the issue.
- **print**: Prints announcement details for testing purposes without creating
actual GitHub issues or sending emails
- **generate**: Updates the compliance file to match the current GCP service
account keys and Secret Manager permissions
diff --git a/infra/enforcement/account_keys.py
b/infra/enforcement/account_keys.py
index a1248e3ee09..3c173d2a8af 100644
--- a/infra/enforcement/account_keys.py
+++ b/infra/enforcement/account_keys.py
@@ -28,6 +28,7 @@ from sending import SendingClient
SECRET_MANAGER_LABEL = "beam-infra-secret-manager"
IAC_DRIFT_SA_KEY = "IAC_DRIFT_SA_KEY"
+ACCOUNT_KEYS_POLICY = "ACCOUNT_KEYS_POLICY"
class AuthorizedUser(TypedDict):
email: str
@@ -385,8 +386,8 @@ class AccountKeysPolicyComplianceCheck:
if general_issues:
self.logger.info(f"Found {len(general_issues)} general compliance
issues. Triggering announcement...")
- title = f"[{IAC_DRIFT_SA_KEY}] Action Required: Unauthorized
Service Accounts Detected"
- body = f"Unauthorized Service Accounts Report\n\n"
+ title = f"[{ACCOUNT_KEYS_POLICY}] Action Required: Service Account
Policy Drift"
+ body = f"Service Account Policy Drift Report\n\n"
body += f"Account keys for project {self.project_id} are not
compliant with the defined policies on {self.service_account_keys_file}\n\n"
for issue in general_issues:
body += f"- {issue}\n"
@@ -423,8 +424,8 @@ class AccountKeysPolicyComplianceCheck:
if general_issues:
self.logger.info("Printing general compliance announcement...")
- title = f"[IAC_DRIFT_SA_KEY] Action Required: Unauthorized Service
Accounts Detected"
- body = f"Unauthorized Service Accounts Report\n\n"
+ title = f"[{ACCOUNT_KEYS_POLICY}] Action Required: Service Account
Policy Drift"
+ body = f"Service Account Policy Drift Report\n\n"
body += f"Account keys for project {self.project_id} are not
compliant with the defined policies on {self.service_account_keys_file}\n\n"
for issue in general_issues:
body += f"- {issue}\n"
diff --git a/infra/enforcement/sending.py b/infra/enforcement/sending.py
index 9d24a816fbc..67857145aea 100644
--- a/infra/enforcement/sending.py
+++ b/infra/enforcement/sending.py
@@ -228,7 +228,7 @@ class SendingClient:
self.logger.info("No compliance issues to report to Github.")
return
- issue_title = "[SECURITY] Action Required: Unmanaged Service Account
Keys Detected"
+ issue_title = "[IAC_DRIFT_SA_KEY] Action Required: Unmanaged Service
Account Keys Detected"
#markdown body
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S
UTC")
new_report = f"### Unmanaged Keys Audit Report ({timestamp})\n"
@@ -238,6 +238,12 @@ class SendingClient:
new_report += f"- {issue_text}\n"
new_report += "\n*Please investigate and revoke these keys if they are
not part of the official rotation system.*"
+ remediation = "\n\n### Remediation\n"
+ remediation += "1. Delete all reported keys as soon as possible.\n"
+ remediation += "2. Replace the deleted keys using the official Beam
key rotation system. It creates the service account key and registers its key
ID and private key in the corresponding managed Secret Manager secret
(`<service-account-id>-key`). Do not create replacement keys manually in IAM.\n"
+ remediation += "3. Run the audit again to confirm that the reported
keys have been removed and the replacement keys are managed by the rotation
system.\n"
+ remediation += "\nFor more information, consult
`infra/keys/README.md`."
+ new_report += remediation
open_issues = self._get_open_issues(issue_title)
if open_issues:
@@ -272,7 +278,7 @@ class SendingClient:
Finds any open security issues regarding rogue keys and automatically
closes them
if the infrastructure is now healthy.
"""
- issue_title = "[SECURITY] Action Required: Unmanaged Service Account
Keys Detected"
+ issue_title = "[IAC_DRIFT_SA_KEY] Action Required: Unmanaged Service
Account Keys Detected"
open_issues = self._get_open_issues(issue_title)
if open_issues:
target_issue = open_issues[0]
diff --git a/infra/enforcement/test_sending.py
b/infra/enforcement/test_sending.py
index 26d4080adec..90104e7bb13 100644
--- a/infra/enforcement/test_sending.py
+++ b/infra/enforcement/test_sending.py
@@ -51,7 +51,7 @@ class TestSendingClient(unittest.TestCase):
"items": [
{
"number": 1234,
- "title": "[SECURITY] Action Required: Unmanaged Service
Account Keys Detected",
+ "title": "[IAC_DRIFT_SA_KEY] Action Required: Unmanaged
Service Account Keys Detected",
"body": "Test body",
"state": "open",
"html_url": "https://github.com/apache/beam/issues/1234",
@@ -64,7 +64,7 @@ class TestSendingClient(unittest.TestCase):
mock_request.side_effect = [mock_response_fail, mock_response_success]
# Call get_open_issues
- issues = self.client._get_open_issues("[SECURITY] Action Required:
Unmanaged Service Account Keys Detected")
+ issues = self.client._get_open_issues("[IAC_DRIFT_SA_KEY] Action
Required: Unmanaged Service Account Keys Detected")
# Verify that two requests were made (one retry)
self.assertEqual(mock_request.call_count, 2)
@@ -79,7 +79,7 @@ class TestSendingClient(unittest.TestCase):
mock_response.json.return_value = {"items": []}
mock_request.return_value = mock_response
- title = "[SECURITY] Action Required: Unmanaged Service Account Keys
Detected"
+ title = "[IAC_DRIFT_SA_KEY] Action Required: Unmanaged Service Account
Keys Detected"
self.client._get_open_issues(title)
# Verify that the query parameter was passed correctly to requests