Browse Source

feat(profiling): Authenticate Profiling requests to Cloud Run (#31973)

Pierre Massat 3 years ago
parent
commit
3d5ec4e313

+ 1 - 0
.github/CODEOWNERS

@@ -179,6 +179,7 @@ build-utils/        @getsentry/owners-js-build
 /static/app/types/profiling.d.ts                                    @getsentry/profiling
 /static/app/utils/profiling                                         @getsentry/profiling
 /tests/js/spec/utils/profiling                                      @getsentry/profiling
+/src/sentry/utils/profiling.py                                      @getsentry/profiling
 /src/sentry/api/endpoints/project_profiling_profile.py              @getsentry/profiling
 /src/sentry/api/endpoints/organization_profiling_profiles.py        @getsentry/profiling
 /tests/sentry/api/endpoints/test_project_profiling_profile.py       @getsentry/profiling

+ 5 - 12
src/sentry/api/endpoints/organization_profiling_profiles.py

@@ -1,14 +1,13 @@
 from typing import Any
 
-from django.conf import settings
 from rest_framework.request import Request
 from rest_framework.response import Response
 
 from sentry import features
 from sentry.api.bases.organization import OrganizationEndpoint
 from sentry.api.paginator import GenericOffsetPaginator
-from sentry.http import safe_urlopen
 from sentry.models import Organization
+from sentry.utils.profiling import get_from_profiling_service, proxy_profiling_service
 
 PROFILE_FILTERS = [
     "android_api_level",
@@ -43,10 +42,8 @@ class OrganizationProfilingProfilesEndpoint(OrganizationEndpoint):
         def data_fn(offset: int, limit: int) -> Any:
             params["offset"] = offset
             params["limit"] = limit
-            response = safe_urlopen(
-                f"{settings.SENTRY_PROFILING_SERVICE_URL}/organizations/{organization.id}/profiles",
-                method="GET",
-                params=params,
+            response = get_from_profiling_service(
+                "GET", f"/organizations/{organization.id}/profiles", params=params
             )
             return response.json().get("profiles", [])
 
@@ -69,10 +66,6 @@ class OrganizationProfilingFiltersEndpoint(OrganizationEndpoint):
         if len(projects) > 0:
             params["project"] = [p.id for p in projects]
 
-        response = safe_urlopen(
-            f"{settings.SENTRY_PROFILING_SERVICE_URL}/organizations/{organization.id}/filters",
-            method="GET",
-            params=params,
+        return proxy_profiling_service(
+            "GET", f"/organizations/{organization.id}/filters", params=params
         )
-
-        return Response(response.json(), status=200)

+ 2 - 7
src/sentry/api/endpoints/project_profiling_profile.py

@@ -1,18 +1,13 @@
-from django.conf import settings
 from rest_framework.request import Request
 from rest_framework.response import Response
 
 from sentry import features
 from sentry.api.bases.project import ProjectEndpoint
-from sentry.http import safe_urlopen
+from sentry.utils.profiling import proxy_profiling_service
 
 
 class ProjectProfilingProfileEndpoint(ProjectEndpoint):
     def get(self, request: Request, project, transaction_id: str) -> Response:
         if not features.has("organizations:profiling", project.organization, actor=request.user):
             return Response(status=404)
-        response = safe_urlopen(
-            f"{settings.SENTRY_PROFILING_SERVICE_URL}/projects/{project.id}/profiles/{transaction_id}",
-            method="GET",
-        )
-        return Response(response.json(), status=response.status_code)
+        return proxy_profiling_service("GET", f"/projects/{project.id}/profiles/{transaction_id}")

+ 34 - 0
src/sentry/utils/profiling.py

@@ -0,0 +1,34 @@
+from typing import Optional
+
+import google.auth.transport.requests
+import google.oauth2.id_token
+from django.conf import settings
+from django.http import HttpResponse
+from requests import Response
+
+from sentry.http import safe_urlopen
+
+
+def get_from_profiling_service(method: str, path: str, params: Optional[dict] = None) -> Response:
+    kwargs = {"method": method}
+    if params:
+        kwargs["params"] = params
+    if settings.ENVIRONMENT == "production":
+        id_token = fetch_id_token_for_service(settings.SENTRY_PROFILING_SERVICE_URL)
+        kwargs["headers"] = {"Authorization": f"Bearer {id_token}"}
+    return safe_urlopen(
+        f"{settings.SENTRY_PROFILING_SERVICE_URL}{path}",
+        **kwargs,
+    )
+
+
+def proxy_profiling_service(method: str, path: str, params: Optional[dict] = None) -> HttpResponse:
+    response = get_from_profiling_service(method, path, params=params)
+    return HttpResponse(
+        content=response.content, status=response.status_code, headers=response.headers
+    )
+
+
+def fetch_id_token_for_service(service_url: str) -> str:
+    auth_req = google.auth.transport.requests.Request()
+    return google.oauth2.id_token.fetch_id_token(auth_req, service_url)