This is unreleased documentation for Admission Controller 1.32-dev.

Writing the validation logic

Critical: Don’t write logging information to STDOUT.

Writing to STDOUT breaks policies. Instead, use STDERR for logging or the logging facility provided by the SUSE Security Admission Controller SDK. The policy’s output to STDOUT must only contain the validation response.

The validation logic goes in the src/index.ts file.

Your validation logic needs to:

  • Get the relevant information from the incoming validation request.

  • Return a response based on the input and the policy settings.

The incoming request contains a JSON object with the Kubernetes resource to validate. You can access this JSON object data through the Admission Controller SDK’s helper functions.

The validate function

The policy provided by the template already has a validate function in src/index.ts. You can use it there, adding your logic to reject Pods with denied hostnames.

This is how the function should look once complete:

/**
 * Validates the incoming request against policy settings.
 * Accepts or rejects the request based on denied hostnames.
 */
function validate(): void {
  try {
    // NOTE 1
    // Read the validation request payload
    const validationRequest = Validation.Validation.readValidationRequest();

    // NOTE 2
    // Extract policy settings from the validation request
    const settings: PolicySettings = validationRequest.settings || {};

    // NOTE 3
    // Extract the Kubernetes object (Pod) from the validation request
    const resource = getKubernetesResource(validationRequest);
    if (!resource) {
      writeOutput(Validation.Validation.rejectRequest('Failed to parse Kubernetes resource.'));
      return;
    }

    // Only process Pod resources
    if (resource.kind !== 'Pod') {
      writeOutput(Validation.Validation.acceptRequest());
      return;
    }

    // NOTE 4
    // Extract hostname from the Pod spec
    const hostname = getPodHostname(resource as Pod);
    const deniedHostnames = settings.denied_hostnames || [];

    // NOTE 5
    // Validate the hostname against the deny list
    if (!hostname) {
      writeOutput(Validation.Validation.acceptRequest());
      return;
    }

    if (deniedHostnames.includes(hostname)) {
      writeOutput(
        Validation.Validation.rejectRequest(
          `Pod hostname '${hostname}' is not allowed. Denied hostnames: [${deniedHostnames.join(', ')}]`
        ),
      );
    } else {
      writeOutput(Validation.Validation.acceptRequest());
    }
  } catch (err) {
    console.error('Validation error:', err);
    writeOutput(Validation.Validation.rejectRequest(`Validation failed: ${err}`));
  }
}

What each NOTE does

  • NOTE 1: Read the incoming validation request using readValidationRequest().

  • NOTE 2: Extract user-defined settings from the validation request (for example, denied hostnames).

  • NOTE 3: Parse the Kubernetes object (expected to be a Pod) from the request payload.

  • NOTE 4: Extract the hostname field from the Pod’s spec section.

  • NOTE 5: Compare the hostname against the denied list and return an appropriate response.

Helper functions

The policy uses several helper functions to process the validation request:

getKubernetesResource

This function extracts the Kubernetes resource from the validation request:

/**
 * Safely parses and extracts the Kubernetes resource from the validation request.
 *
 * @param {ValidationRequest} validationRequest - The validation request object.
 * @returns {KubernetesResource | undefined} The parsed Kubernetes resource if available.
 */
function getKubernetesResource(validationRequest: ValidationRequest): KubernetesResource | undefined {
  try {
    let requestObject: string | KubernetesResource | undefined = validationRequest.request?.object;
    if (typeof requestObject === 'string') {
      requestObject = JSON.parse(requestObject) as unknown as KubernetesResource;
    } else if (requestObject === undefined) {
      return undefined;
    }
    return requestObject as KubernetesResource;
  } catch (error) {
    console.error('Error parsing Kubernetes resource:', error);
    return undefined;
  }
}

This function handles the case where the Kubernetes object is a JSON string or an already parsed object.

getPodHostname

This function extracts the hostname from a Pod resource:

/**
 * Extracts the hostname from a Pod resource.
 *
 * @param {Pod} pod - The Pod resource.
 * @returns {string | undefined} The hostname if set, otherwise undefined.
 */
import type { Pod } from 'kubernetes-types/core/v1';
function getPodHostname(pod: Pod): string | undefined {
  return pod.spec?.hostname;
}

This function extracts the hostname from the Pod’s specification.

Policy entry point

The policy uses a switch statement to handle different actions:

const action = policyAction();
switch (action) {
  case 'validate':
    validate();
    break;
  case 'validate-settings':
    validateSettings();
    break;
  default:
    console.error('Unknown action:', action);
    writeOutput(new Validation.Validation.ValidationResponse(false, 'Unknown policy action'));
}

The Admission Controller Javy plug-in provides the policyAction() function indicating whether the policy should validate a resource or validate its settings.