-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(iam): Eventarc receiver for Service Account Creation (#10596)
* feat(iam): Eventarc receiver for Service Account Creation * remove unused imports * review commetns from averi. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
- Loading branch information
1 parent
36bd4f0
commit 4dd9c1c
Showing
4 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Copyright 2023 Google LLC. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
# [START eventarc_audit_iam_server] | ||
import json | ||
import os | ||
|
||
from cloudevents.http import from_http | ||
from flask import Flask, request | ||
from google.events.cloud.audit import LogEntryData | ||
|
||
app = Flask(__name__) | ||
if __name__ == "__main__": | ||
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080))) | ||
|
||
# [END eventarc_audit_iam_server] | ||
|
||
|
||
# [START eventarc_audit_iam_handler] | ||
@app.route("/", methods=["POST"]) | ||
def index(): | ||
# Transform the HTTP request into a CloudEvent | ||
event = from_http(request.headers, request.get_data()) | ||
|
||
# Extract the LogEntryData from the CloudEvent | ||
# The LogEntryData type is described at https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry | ||
# re-serialize to json, to convert the json-style 'lowerCamelCase' names to the protobuf-style 'snake_case' equivalents. | ||
# ignore_unknown_fields is needed to skip the '@type' fields. | ||
log_entry = LogEntryData.from_json( | ||
json.dumps(event.get_data()), ignore_unknown_fields=True | ||
) | ||
|
||
# Ensure that this event is for service accout key creation, and succeeded. | ||
if log_entry.proto_payload.service_name != "iam.googleapis.com": | ||
return ("Received event was not from IAM.", 400) | ||
if log_entry.proto_payload.status.code != 0: | ||
return ("Key creation failed, not reporting.", 204) | ||
|
||
# Extract relevant fields from the audit log entry. | ||
# Identify the user that requested key creation | ||
user = log_entry.proto_payload.authentication_info.principal_email | ||
|
||
# Extract the resource name from the CreateServiceAccountKey request | ||
# For details of this type, see https://cloud.google.com/iam/docs/reference/rpc/google.iam.admin.v1#createserviceaccountkeyrequest | ||
service_account = log_entry.proto_payload.request["name"] | ||
|
||
# The response is of type google.iam.admin.v1.ServiceAccountKey, | ||
# which is described at https://cloud.google.com/iam/docs/reference/rpc/google.iam.admin.v1#google.iam.admin.v1.ServiceAccountKey | ||
# This key path can be used with gcloud to disable/delete the key: | ||
# e.g. gcloud iam service-accounts keys disable ${keypath} | ||
keypath = log_entry.proto_payload.response["name"] | ||
|
||
print(f"New Service Account Key created for {service_account} by {user}: {keypath}") | ||
return ( | ||
f"New Service Account Key created for {service_account} by {user}: {keypath}", | ||
200, | ||
) | ||
|
||
|
||
# [END eventarc_audit_iam_handler] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Copyright 2023 Google LLC. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
from uuid import uuid4 | ||
|
||
from cloudevents.conversion import to_binary | ||
from cloudevents.http import CloudEvent | ||
|
||
import pytest | ||
|
||
import main | ||
|
||
|
||
ce_attributes = { | ||
"id": str(uuid4), | ||
"type": "com.pytest.sample.event", | ||
"source": "<my-test-source>", | ||
"specversion": "1.0", | ||
} | ||
|
||
|
||
@pytest.fixture | ||
def client(request): | ||
main.app.testing = True | ||
return main.app.test_client() | ||
|
||
|
||
def test_endpoint(client, capsys): | ||
rawobj = { | ||
"protoPayload": { | ||
"@type": "....", | ||
"service_name": "iam.googleapis.com", | ||
"status": { | ||
"code": 0, | ||
}, | ||
"authenticationInfo": {"principalEmail": "user@example.com"}, | ||
"request": { | ||
"name": "projects/-/serviceAccounts/service-account@my-project.iam.gserviceaccount.com" | ||
}, | ||
"response": { | ||
"name": "projects/my-project/serviceAccounts/service-account@my-project.iam.gserviceaccount.com/keys/deadbeef" | ||
}, | ||
}, | ||
} | ||
event = CloudEvent(ce_attributes, rawobj) | ||
headers, body = to_binary(event) | ||
|
||
r = client.post("/", headers=headers, data=body) | ||
assert ( | ||
"New Service Account Key created for projects/-/serviceAccounts/service-account@" | ||
in r.text | ||
) | ||
|
||
assert "by user@example.com" in r.text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pytest==7.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Flask==2.1.0 | ||
gunicorn==20.1.0 | ||
google-events==0.10.0 | ||
cloudevents==1.9.0 | ||
googleapis-common-protos==1.59.0 |