Skip to content

IAM-tilgangspolicyer

En tilgangspolicy gir eller nekter en maskinprincipal — en API-nøkkel eller en Workload Identity-binding — tillatelse til å kalle Frostmoln-API-et. Den er Frostmolns motstykke til en AWS IAM-policy, GCP IAM eller Azure RBAC, men skrevet i Frostmolns eget vokabular.

En policy lar deg uttrykke minste privilegium som en flat scope-liste ikke kan: en enkelt operasjon i stedet for alle compute:write, én ressurs, et kilde-IP-område, et tidsvindu — og eksplisitt deny. For eksempel: en CI-nøkkel som kan opprette instanser, men aldri slette dem; en Terraform-nøkkel som bare virker fra kontornettet ditt; en SDK-nøkkel som bare kan berøre ressurser merket env=staging.

Pilot — tilgang gis per tenant

Forfatting av tilgangspolicyer rulles ut som en pilot. Den er kun tilgjengelig for tenanter der funksjonen er aktivert. Hvis du ikke ser IAM i portalen eller fm iam returnerer not available, er den ennå ikke aktivert for din tenant — kontakt support for å be om tilgang. Dine eksisterende API-nøkler og deres scoper fortsetter å fungere uendret i mellomtiden.

Hvem forfatter policyer

Tilgangspolicyer styrer maskin-principaler, men de forfattes av et menneske innlogget med OIDC (portalen, fm-CLI-en etter fm login, eller Terraform med en OIDC-basert provider). En API-nøkkel eller et workload-identity-token kan ikke opprette, endre eller knytte til en policy — styringsplanet kan aldri låses ute av en policy det selv er underlagt. Dette er bevisst: selv en deny *-policy på din egen nøkkel er gjenopprettbar, fordi du fikser den som et menneske.

Slik fungerer evalueringen

Evalueringen er default-deny:

  1. Hvis en deny-regel matcher, nektes forespørselen — en eksplisitt deny vinner alltid, uavhengig av regelrekkefølge eller hvilken policy den kom fra.
  2. Ellers, hvis en allow-regel matcher, tillates forespørselen.
  3. Ellers nektes forespørselen (implisitt deny).

En forespørsel matcher en regel når dens operasjon matcher en av regelens operations, dens mål-FRN matcher en av regelens targets, og alle regelens constraints holder.

Policy-dokumentet

En policy er et JSON-dokument: en schemaVersion og en liste med rules.

json
{
  "schemaVersion": "1",
  "rules": [
    {
      "name": "compute-read-only",
      "access": "allow",
      "operations": ["compute:instances:read", "compute:instances:list"],
      "targets": ["frn:compute:*:*:instances/*"]
    }
  ]
}

Hver regel har disse feltene:

FeltPåkrevdVerdi
nameneiEn menneskelig etikett for regelen. Fritekst; har ingen effekt på evalueringen.
accessjaallow eller deny.
operationsjaIkke-tom liste med operasjonsmønstre (se Operasjoner).
targetsjaIkke-tom liste med FRN-mønstre (se Mål — FRN).
constraintsneiEkstra betingelser som må holde (se Betingelser).

schemaVersion er strengen "1". Skjemaet er append-only og versjonert som resten av plattformkontrakten — nye funksjoner legges til, aldri omdøpt eller fjernet, slik at en policy du skriver i dag fortsetter å fungere.

Operasjoner

En operasjon navngir én handling i formatet service:resource:action, for eksempel compute:instances:create eller storage:volumes:delete. Hvert segment godtar *-jokertegnet, og jokertegn kollapser på hvert nivå:

  • compute:instances:create — én eksakt operasjon
  • compute:instances:* — alle handlinger på compute-instanser
  • compute:* — alle compute-operasjoner
  • *:*:delete — alle sletthandlinger, på tvers av alle tjenester

Settet av konkrete operasjoner er en server-eid, append-only-katalog — ikke hardkod det, fordi det vokser over tid. Hent den live katalogen:

bash
fm iam catalog                 # all operations
fm iam catalog --filter compute   # only those containing "compute"

eller over HTTP:

bash
curl -H "Authorization: Bearer $TOKEN" \
  https://api.frostmoln.cloud/api/v1/iam/catalog
# → { "operations": ["billing:invoices:create", "compute:instances:create", ... ] }

Portalens policy-bygger presenterer den samme katalogen som en velger.

Mål — FRN

Mål matches mot et Frostmoln Resource Name (FRN) — plattformens ressursnavngivingsskjema, analogt med et AWS ARN:

frn:<service>:<region>:<tenant>:<type>/<id>

I en regels targets skriver du FRN-mønstre, ved å bruke * for å bruke jokertegn på et hvilket som helst segment:

  • * — matcher alle ressurser (bruk sparsomt)
  • frn:compute:*:*:instances/* — enhver compute-instans, denne tenantens
  • frn:storage:*:*:volumes/* — ethvert volum, denne tenantens
  • frn:compute:*:*:instances/i-0a1b2c3d — én bestemt instans

<region>-segmentet må være *

Regionsavgrensede policyer støttes ennå ikke: en forespørsel bærer ingen oppslått region, så et mål som navngir én kan ikke matches pålitelig. Skriv alltid * der — et mål med noe annet avvises når du lagrer policyen. Alle andre segmenter fungerer som beskrevet over.

<tenant>-segmentet er din tenant

La <tenant> stå som *: fordi hver forespørsel bærer din egen tenant, viser * allerede til din tenant og ingen annen. Du kan også skrive din egen tenant-id eksplisitt, men et mål som navngir en annen tenant avvises når du lagrer — det kunne aldri matche, så regelen ville i praksis ikke ha noen effekt.

Betingelser

Betingelser legger vilkår til en regel. En regels constraints er et map nøklet på operator, deretter på betingelsesnøkkel:

json
{
  "name": "read-staging-from-office",
  "access": "allow",
  "operations": ["compute:instances:read"],
  "targets": ["frn:compute:*:*:instances/*"],
  "constraints": {
    "ipInRange": { "frn:sourceIp": ["203.0.113.0/24"] },
    "equals": { "frn:resourceTag/env": "staging" }
  }
}

Betingelsesnøkler

NøkkelBetydning
frn:regionKan ikke brukes ennå. En forespørsel bærer ingen oppslått region, så nøkkelen kan aldri løses: et allow som bruker den gir aldri tilgang, og et deny som bruker den utløses i alle regioner. La den stå ubrukt.
frn:sourceIpKallerens kilde-IP.
frn:tenantTenant-id-en.
frn:principalTypePrincipal-typen: api_key eller workload_identity.
frn:currentTimeForespørselstidspunktet (for before/after).
frn:requestTag/<k>Verdien av forespørselstaggen <k>.
frn:resourceTag/<k>Verdien av taggen <k> på målressursen.

Operatorer og verdiformer

OperatorVerdiformMerknader
equalsen enkelt strengEksakt match.
notEqualsen enkelt strengNegert eksakt match.
likeen enkelt strengGlob-match (*-jokertegn).
ipInRangeen liste med CIDR-strengerBrukes med frn:sourceIp.
beforeet enkelt RFC3339-tidsstempelBrukes med frn:currentTime.
afteret enkelt RFC3339-tidsstempelBrukes med frn:currentTime.

ipInRange er den eneste operatoren som tar en liste; alle andre operatorer tar en enkelt skalar streng. En ukjent nøkkel eller operator, eller en verdi en betingelse ikke kan løse på forespørselstidspunktet, feiler lukket — betingelsen holder ikke (så et allow gir ikke tilgang), og et deny utløses fortsatt.

⚠️ En betingelse på et deny innsnevrer det

Dette er det aller viktigste å få riktig. Betingelser anvendes på samme måte på allow- og deny-regler: en regel matcher bare når dens betingelser holder. Så en betingelse på en deny-regel gjør at deny-en utløses bare når betingelsen er definitivt sann — og lar operasjonen være tillatt når betingelsen er definitivt usann. (En uavklart eller ukjent betingelse utløser likevel deny-en — fail-closed.)

  • For å forby en operasjon ubetinget, skriv en deny-regel uten betingelse.
  • For å begrense en tildeling (til en kilde-IP, et tidsvindu, en ressurstagg), plasser betingelsen på allow-regelen.
json
{
  "schemaVersion": "1",
  "rules": [
    {
      "name": "create-read-from-office",
      "access": "allow",
      "operations": ["compute:instances:create", "compute:instances:read"],
      "targets": ["frn:compute:*:*:instances/*"],
      "constraints": { "ipInRange": { "frn:sourceIp": ["203.0.113.0/24"] } }
    },
    {
      "name": "never-delete",
      "access": "deny",
      "operations": ["compute:instances:delete"],
      "targets": ["*"]
    }
  ]
}

allow-en er nettverksbegrenset av sin betingelse; deny-en er ubetinget, så sletting er alltid forbudt. En betingelse på det deny-et ville ha tillatt sletting når betingelsen var usann.

Forfatte en policy

Forfatt i portalen, med fm-CLI-en, eller med Terraform. En policy skrives én gang og deretter knyttes til en eller flere principaler.

Portal

Åpne IAM → Access Policies, velg New policy, og bruk den veiledede byggeren — velg operasjoner fra katalogen, legg til mål og betingelser, og bruk den innebygde testeren for å sjekke en forespørsel før du lagrer. Åpne deretter en principal (API-nøkkel eller workload identity) og knytt til policyen.

fm CLI

bash
# Create from a file, stdin, or inline JSON
fm iam policy create --name ci-compute-operator --document @policy.json
cat policy.json | fm iam policy create --name ci-compute-operator --document -

# List / inspect / update / delete
fm iam policy list
fm iam policy get <policy-id>
fm iam policy update <policy-id> --document @policy.json
fm iam policy delete <policy-id>

# Attach to a principal (api_key | workload_identity | group)
fm iam policy attach <policy-id> --type api_key --id <key-id>
fm iam policy detach <policy-id> --type api_key --id <key-id>

Terraform

Sett sammen dokumentet med frostmoln_iam_policy_document-datakilden (nativt vokabular — rule / access / operations / targets / constraint), opprett deretter policyen og knytt den til:

hcl
data "frostmoln_iam_policy_document" "ci" {
  # Restrict the grant with a constraint on the ALLOW rule.
  rule {
    name       = "create-read-from-office"
    access     = "allow"
    operations = ["compute:instances:create", "compute:instances:read"]
    targets    = ["frn:compute:*:*:instances/*"]

    constraint {
      operator = "ipInRange"
      key      = "frn:sourceIp"
      values   = ["203.0.113.0/24"]
    }
  }

  # Forbid delete unconditionally — a deny with NO constraint.
  rule {
    name       = "never-delete"
    access     = "deny"
    operations = ["compute:instances:delete"]
    targets    = ["*"]
  }
}

resource "frostmoln_iam_policy" "ci" {
  name        = "ci-compute-operator"
  description = "CI: create/read compute from the office network, never delete"
  document    = data.frostmoln_iam_policy_document.ci.json
}

resource "frostmoln_iam_policy_attachment" "ci_key" {
  policy_id     = frostmoln_iam_policy.ci.id
  attachee_type = "api_key" # or "workload_identity" / "group"
  attachee_id   = frostmoln_api_key.ci.id
}

ipInRange tar en liste med CIDR-er; hver annen operators values er et enkelt element. Datakilden avviser en flerverdiliste på enhver annen operator.

Grupper

For å knytte den samme policyen til flere principaler, opprett en gruppe, legg principaler til den, og knytt policyen til gruppen:

bash
fm iam group create --name ci-keys
fm iam group member add <group-id> --type api_key --id <key-id>
fm iam policy attach <policy-id> --type group --id <group-id>

Et medlem er en api_key eller en workload_identity; en policy knyttes til en api_key, en workload_identity, eller en group.

Test før du lagrer

En feilforfattet policy har reelle tenner i produksjon, så test den først. Testeren (portalbyggeren, eller fm iam simulate) kjører et kandidatdokument mot en hypotetisk forespørsel og returnerer allow eller deny — den lagrer eller håndhever aldri noe:

bash
fm iam simulate --document @policy.json \
  --operation compute:instances:delete --target '*'
# → deny

fm iam simulate --document @policy.json \
  --operation compute:instances:read --target 'frn:compute:*:*:instances/*' \
  --source-ip 203.0.113.10
# → allow

Flagg for betingelseskontekst: --source-ip, --tenant, --principal-type, --request-tag key=value, --resource-tag key=value. Et utelatt betingelsesfelt behandles som uløst / feiler lukket, akkurat som i produksjon. (--region finnes også, men frn:region kan ikke brukes ennå — se Betingelsesnøkler.)

Migrere fra scoper

Dine eksisterende API-nøkkel-scoper (compute:read, storage:write, …) fungerer fortsatt — hver eldre scope evalueres som en tilsvarende syntetisert allow-policy, så det er null tvungen migrering. compute:read oppfører seg som et allow over compute read/list-operasjonene på frn:compute:*.

Du migrerer en nøkkel til en ekte minste-privilegium-policy når du ønsker noe scoper ikke kan uttrykke. For eksempel, ved å erstatte en bred compute:write-scope:

compute:write gir create og update og delete på enhver compute- ressurs, fra hvor som helst. En minste-privilegium-erstatning kan være:

json
{
  "schemaVersion": "1",
  "rules": [
    {
      "name": "create-and-update-from-office",
      "access": "allow",
      "operations": [
        "compute:instances:create",
        "compute:instances:update",
        "compute:instances:read",
        "compute:instances:list"
      ],
      "targets": ["frn:compute:*:*:instances/*"],
      "constraints": { "ipInRange": { "frn:sourceIp": ["203.0.113.0/24"] } }
    },
    {
      "name": "never-delete",
      "access": "deny",
      "operations": ["compute:instances:delete"],
      "targets": ["*"]
    }
  ]
}

Steg:

  1. Forfatt policyen (over) og test den med fm iam simulate mot operasjonene arbeidslasten din faktisk utfører.
  2. Knytt den til nøkkelen.
  3. Innsnevre scopene på nøkkelen (policyen er additiv; både den syntetiserte scope-policyen og din tilknyttede policy evalueres, og ethvert eksplisitt deny vinner). Fjern den brede compute:write-scopen når den tilknyttede policyen dekker det nøkkelen trenger.
  4. Kjør fm iam simulate på nytt (eller følg nøkkelen i portalen) for å bekrefte at tildelingene og nektelsene er som du forventer.

Fordi et eksplisitt deny overstyrer ethvert allow, holder never-delete-regelen over selv mens den eldre scopen fortsatt er til stede — en trygg måte å stramme inn en nøkkel før du er ferdig med å fjerne scopene dens.