Ce document a été traduit à l'aide d'une technologie de traduction automatique. Bien que nous nous efforcions de fournir des traductions exactes, nous ne fournissons aucune garantie quant à l'exhaustivité, l'exactitude ou la fiabilité du contenu traduit. En cas de divergence, la version originale anglaise prévaut et fait foi.

Il s'agit d'une documentation non publiée pour Admission Controller 1.34-dev.

Rédaction de stratégies brutes

Les stratégies brutes sont des stratégies qui peuvent évaluer des documents JSON arbitraires. Pour plus d’informations sur les stratégies brutes, veuillez vous référer à la page stratégies brutes.

Exemples

Les exemples suivants devraient vous sembler familiers si vous avez complété la section validation de ce didacticiel.

N’oubliez pas de marquer la stratégie comme raw en utilisant le champ policyType dans la configuration metadata.yml. Veuillez vous référer à la spécification metadata pour plus d’informations.

metadata.yml avec policyType: raw
rules:
- apiGroups: [""]
  apiVersions: ["v1"]
  resources: ["pods"]
  operations: ["CREATE"]
mutating: false
contextAware: false
executionMode: kubewarden-wapc
policyType: raw
# Consider the policy for the background audit scans. Default is true. Note the
# intrinsic limitations of the background audit feature on docs.kubewarden.io;
# If your policy hits any limitations, set to false for the audit feature to
# skip this policy and not generate false positives.
backgroundAudit: true
annotations:
  # kubewarden specific:
  io.kubewarden.policy.title: policy-name
  io.kubewarden.policy.version: 0.1.0  # should match the OCI tag
  io.kubewarden.policy.description: Short description
  io.kubewarden.policy.author: "Author name <author-email@example.com>"
  io.kubewarden.policy.url: https://github.com/yourorg/policy-name
  io.kubewarden.policy.source: https://github.com/yourorg/policy-name
  io.kubewarden.policy.license: Apache-2.0
  # The next two annotations are used in the policy report generated by the
  # Audit scanner. Severity indicates policy check result criticality and
  # Category indicates policy category. See more here at docs.kubewarden.io
  io.kubewarden.policy.severity: medium # one of info, low, medium, high, critical. See docs.
  io.kubewarden.policy.category: Resource validation
  # artifacthub specific: (optional, to release in Artifact Hub)
  io.kubewarden.policy.ociUrl: ghcr.io/yourorg/policies/policy-name # must match release workflow oci-target
  io.artifacthub.displayName: Policy Name
  io.artifacthub.resources: Pod
  io.artifacthub.keywords: pod, cool policy, kubewarden

Validation

Vous souhaitez rédiger une stratégie qui accepte une demande dans le format suivant :

{
  "request": {
    "user": "alice",
    "action": "delete",
    "resource": "products"
  }
}

et valide que :

  • user est dans la liste des utilisateurs valides

  • action est dans la liste des actions valides

  • resource est dans la liste des ressources valides

Commencez par créer la stratégie en utilisant le modèle de stratégie go. Assurez-vous que tout est en place avec un make, make test et make e2e-tests.

Tout d’abord, définissez les types représentant la charge utile de la demande.

Vous devez déclarer un type RawValidationRequest personnalisé (créez un fichier request.go), contenant les structures RawValidationRequest et Settings, au lieu d’utiliser le type ValidationRequest fourni par le SDK :

// RawValidationRequest represents the request that is sent to the validate function by the Policy Server.
type RawValidationRequest struct {
    Request Request `+json:"request"+`
    // Raw policies can have settings.
    Settings Settings `+json:"settings"+`
}

// Request represents the payload of the request.
type Request struct {
    User     string `+json:"user"+`
    Action   string `+json:"action"+`
    Resource string `+json:"resource"+`
}

Ensuite, vous devez définir le type Settings et les fonctions Valid et validateSettings dans settings.go :

La structure Settings et les fonctions Valid et validateSettings dans settings.go.
// Settings represents the settings of the policy.
type Settings struct {
    ValidUsers     []string `+json:"validUsers"+`
    ValidActions   []string `+json:"validActions"+`
    ValidResources []string `+json:"validResources"+`
}

// Valid returns true if the settings are valid.
func (s *Settings) Valid() (bool, error) {
    if len(s.ValidUsers) == 0 {
        return false, fmt.Errorf("validUsers cannot be empty")
    }

    if len(s.ValidActions) == 0 {
        return false, fmt.Errorf("validActions cannot be empty")
    }

    if len(s.ValidResources) == 0 {
        return false, fmt.Errorf("validResources cannot be empty")
    }

    return true, nil
}

// validateSettings validates the settings.
func validateSettings(payload []byte) ([]byte, error) {
    logger.Info("validating settings")

    settings := Settings{}
    err := json.Unmarshal(payload, &settings)
    if err != nil {
        return kubewarden.RejectSettings(kubewarden.Message(fmt.Sprintf("Provided settings are not valid: %v", err)))
    }

    valid, err := settings.Valid()
    if err != nil {
        return kubewarden.RejectSettings(kubewarden.Message(fmt.Sprintf("Provided settings are not valid: %v", err)))
    }
    if valid {
        return kubewarden.AcceptSettings()
    }

    logger.Warn("rejecting settings")
    return kubewarden.RejectSettings(kubewarden.Message("Provided settings are not valid"))
}

Enfin, vous remplacez la fonction validate (dans validate.go) :

La fonction validate dans validate.go.
func validate(payload []byte) ([]byte, error) {
    // Unmarshal the payload into a RawValidationRequest instance
    validationRequest := RawValidationRequest{}
    err := json.Unmarshal(payload, &validationRequest)
    if err != nil {
        // If the payload is not valid, reject the request
        return kubewarden.RejectRequest(
            kubewarden.Message(err.Error()),
            kubewarden.Code(400))
    }

    request := validationRequest.Request
    settings := validationRequest.Settings

    // Validate the payload
    if slices.Contains(settings.ValidUsers, request.User) &&
        slices.Contains(settings.ValidActions, request.Action) &&
        slices.Contains(settings.ValidResources, request.Resource) {
        return kubewarden.AcceptRequest()
    }

    return kubewarden.RejectRequest(
        kubewarden.Message("The request cannot be accepted."),
        kubewarden.Code(400))
}

Vous pouvez configurer un test dans e2e.bats :

e2e.bats
#!/usr/bin/env bats

@test "accept" {
  run kwctl run annotated-policy.wasm -r test_data/request.json -s test_data/settings.json

  # this prints the output when one the checks below fails
  echo "output = ${output}"

  # request allowed
  [ "$status" -eq 0 ]
  [ $(expr "$output" : '.*allowed.*true') -ne 0 ]
}

Alors les sorties de make, make test et make e2e sont :

Sorties
make && make test && make e2e-tests
docker run \
    --rm \
    -e GOFLAGS="-buildvcs=false" \
    -v /home/jhk/projects/suse/tmp/fab-goraw:/src \
    -w /src tinygo/tinygo:0.30.0 \
    tinygo build -o policy.wasm -target=wasi -no-debug .
go test -v
=== RUN   TestAcceptValidSettings
--- PASS: TestAcceptValidSettings (0.00s)
=== RUN   TestRejectSettingsWithEmptyValidUsers
--- PASS: TestRejectSettingsWithEmptyValidUsers (0.00s)
=== RUN   TestRejectSettingsWithEmptyValidActions
--- PASS: TestRejectSettingsWithEmptyValidActions (0.00s)
=== RUN   TestRejectSettingsWithEmptyValidResources
--- PASS: TestRejectSettingsWithEmptyValidResources (0.00s)
=== RUN   TestValidateRequestAccept
--- PASS: TestValidateRequestAccept (0.00s)
=== RUN   TestValidateRequestReject
--- PASS: TestValidateRequestReject (0.00s)
PASS
ok      github.com/kubewarden/go-policy-template    0.002s
kwctl annotate -m metadata.yml -u README.md -o annotated-policy.wasm policy.wasm
bats e2e.bats
e2e.bats
 ✓ accept

1 test, 0 failures

Mutation

Vous devez modifier l’exemple précédent pour appliquer une mutation à la demande au lieu de la rejeter. Les paramètres doivent contenir le defaultUser, defaultAction et defaultRequest à utiliser pour appliquer une mutation à la demande si l’utilisateur, l’action ou la ressource n’est pas valide.

Vous devez mettre à jour le type Settings avec les nouveaux champs :

// Settings defines the settings of the policy.
type Settings struct {
    ValidUsers      []string `+json:"validUsers"+`
    ValidActions    []string `+json:"validActions"+`
    ValidResources  []string `+json:"validResources"+`
    DefaultUser     string   `+json:"defaultUser"+`
    DefaultAction   string   `+json:"defaultAction"+`
    DefaultResource string   `+json:"defaultResource"+`
}

// Valid returns true if the settings are valid.
func (s *Settings) Valid() (bool, error) {
    if len(s.ValidUsers) == 0 {
        return false, fmt.Errorf("validUsers cannot be empty")
    }

    if len(s.ValidActions) == 0 {
        return false, fmt.Errorf("validActions cannot be empty")
    }

    if len(s.ValidResources) == 0 {
        return false, fmt.Errorf("validResources cannot be empty")
    }

    if s.DefaultUser == "" {
        return false, fmt.Errorf("defaultUser cannot be empty")
    }

    if s.DefaultAction == "" {
        return false, fmt.Errorf("defaultUser cannot be empty")
    }

    if s.DefaultResource == "" {
        return false, fmt.Errorf("defaultResource cannot be empty")
    }

    return true, nil
}

Aussi, la fonction validate pour introduire la mutation :

func validate(payload []byte) ([]byte, error) {
    // Unmarshal the payload into a RawValidationRequest instance
    validationRequest := RawValidationRequest{}
    err := json.Unmarshal(payload, &validationRequest)
    if err != nil {
        // If the payload is not valid, reject the request
        return kubewarden.RejectRequest(
            kubewarden.Message(err.Error()),
            kubewarden.Code(400))
    }

    request := validationRequest.Request
    settings := validationRequest.Settings

    logger.Info("validating request")

    // Accept the request without mutating it if it is valid
    if slices.Contains(settings.ValidUsers, request.User) &&
        slices.Contains(settings.ValidActions, request.Action) &&
        slices.Contains(settings.ValidResources, request.Resource) {
        return kubewarden.AcceptRequest()
    }

    logger.Info("mutating request")

    // Mutate the request if it is not valid
    if !slices.Contains(settings.ValidUsers, request.User) {
        request.User = settings.DefaultUser
    }

    if !slices.Contains(settings.ValidActions, request.Action) {
        request.Action = settings.DefaultAction
    }

    if !slices.Contains(settings.ValidResources, request.Resource) {
        request.Resource = settings.DefaultResource
    }

    return kubewarden.MutateRequest(request)
}