- Add Implementation Status section to A2H2A spec - Clarify Google Chat is notification-only - Add target approval architecture requirements - Add critical A2H2A safety principle to RUNBOOK.md - Remove unsafe approval/rejection endpoints from server.py - Enforce server-side parameter_hash calculation - Disable execution for all tools in A2H2A_TOOL_ALLOW_LIST
246 lines
11 KiB
Markdown
246 lines
11 KiB
Markdown
# OSVxCC Runbook
|
|
|
|
> Dette dokumentet beskriver operasjonelle prosedyrer for å håndtere varsler og verifisere systemstatus. Målet er å raskt avklare om en hendelse er reell eller en falsk positiv.
|
|
|
|
---
|
|
|
|
## Innholdsfortegnelse
|
|
|
|
1. [Varsel: "Ukjent bruker" Git Push](#varsel-ukjent-bruker-git-push)
|
|
2. [Hendelse: Eksponert Hemmelighet](#hendelse-eksponert-hemmelighet)
|
|
3. [Hendelse: Høy andel HTTP 401/403 på Cloud Run](#hendelse-høy-andel-http-401403-på-cloud-run)
|
|
4. [Hendelse: HTTP 50x (Cloud Run nede)](#hendelse-http-50x-cloud-run-nede)
|
|
5. [Hendelse: VPC Service Controls blokkerer tilgang](#hendelse-vpc-service-controls-blokkerer-tilgang)
|
|
6. [Hendelse: Cloud Build / Binary Authorization feiler deploy](#hendelse-cloud-build--binary-authorization-feiler-deploy)
|
|
|
|
---
|
|
|
|
## 1. Varsel: "Ukjent bruker" Git Push
|
|
|
|
### Symptom
|
|
|
|
Chat-applikasjonen (f.eks. Slack, Discord) rapporterer gjentatte Git-pushes fra en "ukjent bruker" eller en generisk app-bruker (f.eks. "CodeOSS-push, App"). Aktiviteten skjer ofte på faste tidspunkter (f.eks. 09:00 og 21:00).
|
|
|
|
### Undersøkelsesprosedyre
|
|
|
|
Følg disse stegene for å verifisere aktiviteten:
|
|
|
|
1. **Sjekk Git-loggen umiddelbart.**
|
|
```bash
|
|
git log -n 10 --pretty=format:"%h %an <%ae> %ar: %s"
|
|
```
|
|
- **Se etter:** Er de siste comittene fra en kjent og autorisert bidragsyter (f.eks. `Chris Christiansen <chris.christiansen@vauco.no>`)?
|
|
|
|
2. **Analyser tidspunkt og innhold.**
|
|
- **Spørsmål:** Samsvarer tidspunktene med normalt utviklingsarbeid? Er commit-meldingene og filendringene logiske?
|
|
|
|
3. **Verifiser webhook-konfigurasjon.**
|
|
- **Undersøk:** Sjekk innstillingene for webhooken i Gitea/GitHub og i chat-applikasjonen. Ofte kan webhooks være konfigurert slik at de ikke klarer å mappe den tekniske brukeren til et visningsnavn, og faller tilbake på et generisk navn.
|
|
|
|
4. **Kontroller automatiserte systemer (for å utelukke dem).**
|
|
- Sjekk Cloud Build-triggere, cron-jobs på VM-en, og eventuelle lokale Git hooks for uventet aktivitet.
|
|
|
|
### Konklusjon (Mest sannsynlig)
|
|
|
|
**Ingen sikkerhetshendelse.** Aktiviteten er høyst sannsynlig legitimt utviklingsarbeid utført av en autorisert bruker via en IDE (som VS Code) sin Git-integrasjon. "Ukjent bruker"-navnet er et resultat av hvordan webhooken tolker og presenterer hendelsen.
|
|
|
|
### Status
|
|
|
|
✅ **Avklart — Falsk positiv.** Ingen tiltak er nødvendig med mindre `git log` viser ukjente forfattere.
|
|
|
|
---
|
|
|
|
## 2. Hendelse: Eksponert Hemmelighet
|
|
|
|
### Symptom
|
|
|
|
En hemmelighet (API-nøkkel, passord, tjenestenøkkel) er oppdaget på et usikret sted. Eksempler:
|
|
- Limt inn i en offentlig chat (Slack, Discord).
|
|
- Sjekket inn i Git og pushet til Gitea/GitHub.
|
|
- Hardkodet i en offentlig tilgjengelig fil.
|
|
|
|
**Dette er en KRITISK hendelse.**
|
|
|
|
### Undersøkelsesprosedyre (PICERL-fasene)
|
|
|
|
#### Fase 1: Containment (Innkapsling) - UMIDDELBART
|
|
|
|
1. **Roter hemmeligheten umiddelbart.** Dette er det viktigste steget for å stoppe misbruk.
|
|
1. **Generer en ny verdi** for hemmeligheten.
|
|
2. **Opprett en ny versjon** i Secret Manager med den nye verdien. Se `docs/SECRET_MANAGEMENT.md` for detaljerte kommandoer.
|
|
```bash
|
|
# Eksempel for mcp-server-key
|
|
printf "<NY_HEMMELIG_VERDI>" | gcloud secrets versions add mcp-server-key --data-file=-
|
|
```
|
|
3. **Oppdater applikasjonen(e)** som bruker hemmeligheten til å peke mot den nye versjonen (`latest`). For Cloud Run, deploy en ny revisjon med den oppdaterte hemmelighetsreferansen.
|
|
4. **Deaktiver den gamle versjonen** i Secret Manager. **Ikke slett den ennå.** Dette fungerer som en "kill switch".
|
|
```bash
|
|
gcloud secrets versions disable <GAMMEL_VERSJON> --secret=<HEMMELIGHETENS_NAVN>
|
|
```
|
|
|
|
#### Fase 2: Eradication (Utryddelse)
|
|
|
|
1. **Fjern hemmeligheten fra eksponeringsstedet.**
|
|
- **Git:** Bruk et verktøy som `git-filter-repo` eller `BFG Repo-Cleaner` for å fjerne hemmeligheten fra **hele** Git-historikken. En vanlig `git commit` er **ikke** nok.
|
|
- *Referanse: Den tidligere hendelsen med `mcp-server-key` (se `docs/SECURITY_AUDITS.md`).*
|
|
- **Slack/Chat:** Slett meldingen.
|
|
- **Filer:** Fjern hemmeligheten fra filen og deploy på nytt.
|
|
|
|
#### Fase 3: Recovery & Lessons Learned
|
|
|
|
1. **Analyser logger.** Sjekk Secret Manager audit logs for å se om den eksponerte hemmeligheten ble aksessert av uautoriserte IP-adresser eller tjenestekontoer.
|
|
- Naviger til `Logging > Log Explorer` i Cloud Console.
|
|
- Query:
|
|
```
|
|
resource.type="gcp_secret"
|
|
protoPayload.methodName="AccessSecretVersion"
|
|
protoPayload.resourceName="projects/.../secrets/<HEMMELIGHETENS_NAVN>/versions/<GAMMEL_VERSJON>"
|
|
```
|
|
2. **Verifiser at alle systemer fungerer** med den nye hemmeligheten.
|
|
3. **Destruer den gamle versjonen** i Secret Manager etter en verifikasjonsperiode (f.eks. 24-48 timer).
|
|
4. **Dokumenter hendelsen** og diskuter hvordan det skjedde for å forhindre gjentakelse.
|
|
|
|
### Status
|
|
|
|
🔴 **KRITISK TIL AVKLART.** Følg prosedyren til alle steg er fullført.
|
|
|
|
---
|
|
|
|
## 3. Hendelse: Høy andel HTTP 401/403 på Cloud Run
|
|
|
|
### Symptom
|
|
|
|
Cloud Monitoring-varsler rapporterer en unormalt høy andel av HTTP-responser med statuskode 401 (Unauthorized) eller 403 (Forbidden) fra MCP-serveren (opax-mcp).
|
|
|
|
### Undersøkelsesprosedyre
|
|
|
|
1. **Analyser kildene.**
|
|
- Gå til `Logging > Log Explorer` i Cloud Console.
|
|
- Kjør en spørring for å gruppere 401/403-feil etter kilde-IP.
|
|
```
|
|
resource.type="cloud_run_revision"
|
|
resource.labels.service_name="opax-mcp"
|
|
httpRequest.status IN (401, 403)
|
|
```
|
|
- Se i loggene etter `jsonPayload.remoteIp`.
|
|
2. **Skill mellom angrep og feilkonfigurasjon.**
|
|
- **Brute-force/Scanning:** Ser du mange forespørsler fra **én eller få IP-adresser** som ikke er gjenkjennelige? Dette kan tyde på et angrepsforsøk. Vurder å blokkere IP-en midlertidig med Cloud Armor.
|
|
- **Feilkonfigurert klient:** Ser du forespørsler fra **kjente IP-adresser** (f.eks. andre VM-er i prosjektet)? Dette tyder på at en legitim klient bruker en utdatert eller feilaktig hemmelighet (`X-MCP-Secret`).
|
|
- **Mønster:** Er feilene sporadiske eller konstante? Konstante feil fra en kjent klient indikerer nesten alltid en konfigurasjonsfeil hos klienten.
|
|
|
|
### Konklusjon (Mest sannsynlig)
|
|
|
|
- **Scenario A (Ukjent IP):** Potensielt sikkerhetsproblem (scanning). Overvåk og vurder blokkering.
|
|
- **Scenario B (Kjent IP):** Operasjonell feil. Informer eieren av klienten om å oppdatere sin hemmelighet.
|
|
|
|
### Status
|
|
|
|
🟡 **MODERAT TIL AVKLART.**
|
|
|
|
---
|
|
|
|
## 4. Hendelse: HTTP 50x (Cloud Run nede)
|
|
|
|
### Symptom
|
|
|
|
Cloud Monitoring varsler om en høy andel HTTP 5xx-feil, eller tjenesten svarer ikke. Dette indikerer at containeren krasjer eller ikke starter.
|
|
|
|
### Undersøkelsesprosedyre
|
|
|
|
1. **Sjekk container-logger for krasj.**
|
|
- Gå til `Cloud Run > opax-mcp > Logs`.
|
|
- Se etter meldinger som indikerer at prosessen stoppet uventet, f.eks. `panic`, `out of memory`, eller andre unntak ved oppstart.
|
|
2. **Verifiser IAM-tilganger (spesielt til Secret Manager).**
|
|
- Gå til `Cloud Run > opax-mcp > Revisions`.
|
|
- Sjekk hvilken Service Account som brukes (skal være `jason-vauger@...`).
|
|
- Gå til `IAM & Admin > IAM`.
|
|
- Verifiser at `jason-vauger@...` har rollen `roles/secretmanager.secretAccessor`.
|
|
- **Vanlig feil:** Hvis applikasjonen ikke får hentet `mcp-server-key` ved oppstart på grunn av manglende IAM-tilgang, vil den ofte krasje med en 5xx-feil.
|
|
3. **Analyser nylige endringer.**
|
|
- Har det vært en nylig deployering? Rull tilbake til en tidligere, fungerende revisjon via `Cloud Run > opax-mcp > Manage Revisions` for å se om problemet vedvarer.
|
|
|
|
### Konklusjon (Mest sannsynlig)
|
|
|
|
- Oftest er dette enten en **bug i koden** (som fører til krasj) eller en **IAM/Secret Manager-konfigurasjonsfeil**.
|
|
|
|
### Status
|
|
|
|
🔴 **KRITISK TIL AVKLART.**
|
|
|
|
---
|
|
|
|
## 5. Hendelse: VPC Service Controls blokkerer tilgang
|
|
|
|
### Symptom
|
|
|
|
En applikasjon, et skript eller en utvikler mottar en `403 Request Prohibited by organization's policy` feil ved kall mot en GCP API (f.eks. BigQuery, Storage) som er beskyttet av en VPC-SC perimeter.
|
|
|
|
### Undersøkelsesprosedyre
|
|
|
|
1. **Finn VPC-SC brudd-loggen.**
|
|
- Gå til `Logging > Log Explorer`.
|
|
- Bruk følgende spørring for å finne de relevante loggene:
|
|
```
|
|
log_id("cloudaudit.googleapis.com/activity")
|
|
protoPayload.metadata.violationReason = "SERVICE_NOT_ALLOWED_FROM_VPC" OR "NO_MATCHING_ACCESS_LEVEL"
|
|
```
|
|
2. **Analyser logg-detaljene.**
|
|
- `resource.labels.project_id`: Hvilket prosjekt skjedde bruddet i?
|
|
- `protoPayload.authenticationInfo.principalEmail`: Hvem eller hva ble blokkert?
|
|
- `protoPayload.requestMetadata.callerIp`: Hvor kom kallet fra (hvis relevant)?
|
|
- `protoPayload.resourceName`: Hvilken beskyttet ressurs var målet?
|
|
|
|
### Konklusjon (Mest sannsynlig)
|
|
|
|
- **Scenario A (Legitimt kall blokkert):** En ny tjeneste eller utvikler-VM er satt opp utenfor perimeteren og trenger tilgang. **Tiltak:** Vurder å inkludere ressursen i perimeteren, eller opprett et tilgangsnivå (Access Level).
|
|
- **Scenario B (Uventet kall blokkert):** Et uautorisert skript eller en ekstern tjeneste prøver å nå en beskyttet ressurs. **Konklusjon:** Perimeteren har fungert som designet og forhindret et potensielt datainnbrudd.
|
|
|
|
### Status
|
|
|
|
🟡 **MODERAT TIL AVKLART.** Krever analyse for å skille mellom feilkonfigurasjon og reell beskyttelse.
|
|
|
|
---
|
|
|
|
## 6. Hendelse: Cloud Build / Binary Authorization feiler deploy
|
|
|
|
### Symptom
|
|
|
|
En Cloud Build-pipeline feiler på det siste "deploy to Cloud Run"-steget. Feilmeldingen nevner `Binary Authorization` eller `attestation`.
|
|
|
|
### Undersøkelsesprosedyre
|
|
|
|
1. **Sjekk bygge-loggen for TYR-feil.**
|
|
- Åpne loggen for den feilede builden i Cloud Build.
|
|
- Scroll opp til steget som kjører **TYR Compliance Scan**.
|
|
- Hvis dette steget feilet (rødt ikon), vil loggen inneholde detaljer om nøyaktig hvilken compliance-regel som ble brutt.
|
|
2. **Verifiser at attestering finnes.**
|
|
- Hvis TYR-steget var vellykket, men deploy likevel feiler, kan selve attesteringen mangle.
|
|
- Finn "digest" for ditt image i loggen (en lang `sha256:...` streng).
|
|
- Kjør denne kommandoen i Cloud Shell:
|
|
```bash
|
|
gcloud container binauthz attestations list --artifact-url="[REGION]-docker.pkg.dev/[PROJECT_ID]/[REPO]/[IMAGE_NAME]@[IMAGE_DIGEST]"
|
|
```
|
|
|
|
### Konklusjon (Mest sannsynlig)
|
|
|
|
- **TYR-feil:** Den vanligste årsaken. En endring i koden eller infrastrukturen bryter med en definert sikkerhetsregel. **Tiltak:** Rett feilen som TYR rapporterer.
|
|
- **Manglende attestering:** Output fra `gcloud` er tomt. Dette kan skyldes en midlertidig feil med KMS eller at IAM-rettighetene til Cloud Build sin service account er feil. **Tiltak:** Prøv å kjøre builden på nytt. Hvis feilen vedvarer, sjekk IAM for `cloud-build-private-pool@...`.
|
|
|
|
### Status
|
|
|
|
🟡 **MODERAT TIL AVKLART.** Vanligvis en operasjonell feil forårsaket av en compliance-endring.
|
|
|
|
---
|
|
|
|
## 7. Sikkerhet og Hendelseshåndtering
|
|
|
|
Se følgende dokumenter for detaljerte prosedyrer:
|
|
|
|
- `docs/SECURITY.md`: Overordnet sikkerhetsarkitektur.
|
|
- `docs/INCIDENT_RESPONSE.md`: Prosedyrer for håndtering av sikkerhetshendelser.
|
|
- `docs/SECRET_MANAGEMENT.md`: Retningslinjer for håndtering av secrets.
|
|
|
|
### Kritisk Sikkerhetsprinsipp for A2H2A
|
|
|
|
**No privileged action may be authorized by a notification, a URL parameter, or a client-supplied identity. Approval requires a verified identity boundary and server-side validation of an immutable ticket.**
|