本文档采用自动化机器翻译技术翻译。 尽管我们力求提供准确的译文,但不对翻译内容的完整性、准确性或可靠性作出任何保证。 若出现任何内容不一致情况,请以原始 英文 版本为准,且原始英文版本为权威文本。

这是尚未发布的文档。 Admission Controller 1.34-dev.

原始策略

原始策略是可以评估任意 JSON 文档的策略。 有关原始策略的更多信息,请参阅 raw policies 页面。

示例

如果您完成了本教程的 validation 页面,以下示例应该很熟悉。

请记得在 metadata.yml 配置中使用 policyType 字段,将策略标记为 raw。 有关更多信息,请参阅 metadata 规范。

Validation

让我们编写一个接受以下格式请求的策略:

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

并验证:

  • user 在有效用户列表中

  • action 在有效操作列表中

  • resource 在有效资源列表中

首先使用 rust policy template 来搭建策略。

首先,我们定义表示请求有效负载的类型。 我们将声明一个自定义 RawValidationRequest 类型,该类型包含 RequestSettings,而不是使用 SDK 提供的 ValidationRequest 类型:

/// RawValidationRequest represents the request that is sent to the validate function by the Policy Server.
#[derive(Deserialize)]
pub(crate) struct RawValidationRequest {
    pub(crate) request: Request,
    pub(crate) settings: Settings,
}

#[derive(Serialize, Deserialize)]
/// Request represents the payload of the request.
pub(crate) struct Request {
    pub(crate) user: String,
    pub(crate) resource: String,
    pub(crate) action: String,
}

然后我们需要定义 Settings 类型并实现 Validatable 特性:

/// Settings represents the settings of the policy.
#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(default, rename_all = "camelCase")]
pub(crate) struct Settings {
    pub(crate) valid_users: Vec<String>,
    pub(crate) valid_actions: Vec<String>,
    pub(crate) valid_resources: Vec<String>,
}

impl kubewarden::settings::Validatable for Settings {
    fn validate(&self) -> Result<(), String> {
        info!(LOG_DRAIN, "starting settings validation");

        if self.valid_users.is_empty() {
            return Err("validUsers cannot be empty".to_string());
        }

        if self.valid_actions.is_empty() {
            return Err("validActions cannot be empty".to_string());
        }

        if self.valid_resources.is_empty() {
            return Err("validResources cannot be empty".to_string());
        }

        Ok(())
    }
}

最后,我们定义 validate 函数:

fn validate(payload: &[u8]) -> CallResult {
    let validation_request: RawValidationRequest =
        if let Ok(validation_request) = serde_json::from_slice(payload) {
            validation_request
        } else {
            return kubewarden::reject_request(
                Some("cannot unmarshal request".to_string()),
                None,
                None,
                None,
            );
        };

    info!(LOG_DRAIN, "starting validation");

    let request = validation_request.request;
    let settings = validation_request.settings;

    if settings.valid_users.contains(&request.user)
        && settings.valid_actions.contains(&request.action)
        && settings.valid_resources.contains(&request.resource)
    {
        info!(LOG_DRAIN, "accepting resource");
        kubewarden::accept_request()
    } else {
        kubewarden::reject_request(
            Some("this request is not accepted".to_string()),
            None,
            None,
            None,
        )
    }
}

变更

让我们修改之前的示例,以便变更请求而不是拒绝它。 在这种情况下,设置将包含`defaultUser`、defaultAction`和`defaultRequest,如果用户、操作或资源无效,将用于变更请求。

我们需要用新字段更新`Settings`类型:

/// Settings represents the settings of the policy.
#[derive(Serialize, Deserialize, Default, Debug)]
#[serde(default, rename_all = "camelCase")]
pub(crate) struct Settings {
    pub(crate) valid_users: Vec<String>,
    pub(crate) valid_actions: Vec<String>,
    pub(crate) valid_resources: Vec<String>,
    pub(crate) default_user: String,
    pub(crate) default_action: String,
    pub(crate) default_resource: String,
}

impl kubewarden::settings::Validatable for Settings {
    fn validate(&self) -> Result<(), String> {
        info!(LOG_DRAIN, "starting settings validation");

        if self.valid_users.is_empty() {
            return Err("validUsers cannot be empty".to_string());
        }

        if self.valid_actions.is_empty() {
            return Err("validActions cannot be empty".to_string());
        }

        if self.valid_resources.is_empty() {
            return Err("validResources cannot be empty".to_string());
        }

        if self.default_user.is_empty() {
            return Err("defaultUser cannot be empty".to_string());
        }

        if self.default_action.is_empty() {
            return Err("defaultAction cannot be empty".to_string());
        }

        if self.default_resource.is_empty() {
            return Err("defaultResource cannot be empty".to_string());
        }

        Ok(())
    }
}

以及 validate 函数以引入变更:

fn validate(payload: &[u8]) -> CallResult {
    let validation_request: RawValidationRequest =
        if let Ok(validation_request) = serde_json::from_slice(payload) {
            validation_request
        } else {
            return kubewarden::reject_request(
                Some("cannot unmarshal request".to_string()),
                None,
                None,
                None,
            );
        };

    info!(LOG_DRAIN, "starting validation");

    let request = validation_request.request;
    let settings = validation_request.settings;

    if settings.valid_users.contains(&request.user)
        && settings.valid_actions.contains(&request.action)
        && settings.valid_resources.contains(&request.resource)
    {
        info!(LOG_DRAIN, "accepting request");
        return kubewarden::accept_request();
    }

    info!(LOG_DRAIN, "mutating request");
    let mut request = request;

    if !settings.valid_users.contains(&request.user) {
        request.user = settings.default_user;
    }

    if !settings.valid_actions.contains(&request.action) {
        request.action = settings.default_action;
    }

    if !settings.valid_resources.contains(&request.resource) {
        request.resource = settings.default_resource;
    }

    let mutated_request = serde_json::to_value(request)?;
    kubewarden::mutate_request(mutated_request)
}