上一篇我们说了,初始化一个 kube-apiserver 首先需要创建 kubeAPIServerConfig,而 kubeAPIServerConfig 的重点又在创建 genericConfig 上,genericConfig 创建流程包括 etcd 配置初始化,认证初始化,鉴权初始化,审计初始化,准入初始化,流控初始化。
这一篇我们来说说审计初始化,准入初始化,流控初始化。
审计初始化
// cmd/kube-apiserver/app/server.go
func buildGenericConfig(
s *options.ServerRunOptions,
proxyTransport *http.Transport,
) (...) {
lastErr = s.Audit.ApplyTo(genericConfig)
if lastErr != nil {
return
}
}
下面是初始化审计的步骤,包括
- 规则评估器创建
- 日志存储后端创建(在本地保存日志)
- webhook 后端创建(远程保存或处理日志)
func (o *AuditOptions) ApplyTo(
c *server.Config,
) error {
...
// 1. Build policy evaluator
evaluator, err := o.newPolicyRuleEvaluator()
if err != nil {
return err
}
// 2. Build log backend
var logBackend audit.Backend
w, err := o.LogOptions.getWriter()
if err != nil {
return err
}
if w != nil {
if evaluator == nil {
klog.V(2).Info("No audit policy file provided, no events will be recorded for log backend")
} else {
logBackend = o.LogOptions.newBackend(w)
}
}
// 3. Build webhook backend
var webhookBackend audit.Backend
if o.WebhookOptions.enabled() {
if evaluator == nil {
klog.V(2).Info("No audit policy file provided, no events will be recorded for webhook backend")
} else {
if c.EgressSelector != nil {
var egressDialer utilnet.DialFunc
egressDialer, err = c.EgressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext())
if err != nil {
return err
}
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(egressDialer)
} else {
webhookBackend, err = o.WebhookOptions.newUntruncatedBackend(nil)
}
if err != nil {
return err
}
}
}
groupVersion, err := schema.ParseGroupVersion(o.WebhookOptions.GroupVersionString)
if err != nil {
return err
}
// 4. Apply dynamic options.
var dynamicBackend audit.Backend
if webhookBackend != nil {
// if only webhook is enabled wrap it in the truncate options
dynamicBackend = o.WebhookOptions.TruncateOptions.wrapBackend(webhookBackend, groupVersion)
}
// 5. Set the policy rule evaluator
c.AuditPolicyRuleEvaluator = evaluator
// 6. Join the log backend with the webhooks
c.AuditBackend = appendBackend(logBackend, dynamicBackend)
if c.AuditBackend != nil {
klog.V(2).Infof("Using audit backend: %s", c.AuditBackend)
}
return nil
}
审计策略创建
所谓审计策略,就是根据用户提供的审计配置文件,提取需要记录到审计日志的规则,即什么请求的什么阶段和什么资源的什么操作需要记录,审计策略配置文件可以通过如下参数指定
--audit-policy-file="/path/to/audit/policy"
该文件主要包含了什么事件、什么数据需要被记录
,具体的配置可以参考官方说明
前面我们在介绍认证、鉴权的时候也说到了,他们是在请求处理前在 DefaultBuildHandlerChain 这条链上被执行的,我们这说的审计在请求处理被处理前也是在这条链上执行的
func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
...
handler = filterlatency.TrackCompleted(handler)
handler = genericapifilters.WithAudit(handler, c.AuditBackend, c.AuditPolicyRuleEvaluator, c.LongRunningFunc)
handler = filterlatency.TrackStarted(handler, "audit")
...
}
审计执行分为下面几个阶段
const (
StageRequestReceived Stage = "RequestReceived"
StageResponseStarted Stage = "ResponseStarted"
StageResponseComplete Stage = "ResponseComplete"
StagePanic Stage = "Panic"
)
可以在 --audit-policy-file 参数指定的配置中指定哪些规则需要在哪些特定执行审计,或者忽略哪些阶段。在 DefaultBuildHandlerChain 执行的是 RequestReceived 阶段的审计日志记录。
审计后端创建
这里所谓的后端就是审计日志存储的驱动。他通过下面接口来定义
type Sink interface {
ProcessEvents(events ...*auditinternal.Event) bool
}
type Backend interface {
Sink
Run(stopCh