Documentation
¶
Overview ¶
Package controller provides the Kubernetes controller for watching pods and managing eBPF program attachments.
Index ¶
- Constants
- func TrustedDNSServers(ctx context.Context, reader client.Reader, static []net.IP, ...) []net.IP
- type Container
- type NRIPlugin
- type Preparer
- type Reconciler
- func (r *Reconciler) GetTrackedPodCount() int
- func (r *Reconciler) PrepareContainer(ctx context.Context, sb *Sandbox, c *Container)
- func (r *Reconciler) PrepareSandbox(ctx context.Context, sb *Sandbox) bool
- func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error)
- func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error
- type Sandbox
- type SecretReconciler
- type SecretSyncReconciler
- type TrustedDNSReconciler
Constants ¶
const ( // AnnotationEnabled is the annotation that enables Kloak for a pod. AnnotationEnabled = "getkloak.io/enabled" // CgroupBasePath is the base path for cgroups v2. CgroupBasePath = "/sys/fs/cgroup" )
const ( // AnnotationSecretEnabled is the label/annotation to enable Kloak secret replication. AnnotationSecretEnabled = "getkloak.io/enabled" // AnnotationPort is the annotation to specify an allowed port for a secret. AnnotationPort = "getkloak.io/port" // AnnotationHosts is the annotation to specify allowed hosts for a secret. AnnotationHosts = "getkloak.io/hosts" // ShadowSecretSuffix is the suffix appended to the name of the shadow secret. ShadowSecretSuffix = "-kloak" )
const ( KubeDNSNamespace = "kube-system" KubeDNSName = "kube-dns" )
The cluster DNS Service, whose answers the data plane trusts.
const ( // DefaultNRISocket is where containerd (2.0+) and CRI-O (1.30+) serve // NRI by default. DefaultNRISocket = "/var/run/nri/nri.sock" )
const DefaultSecretResyncPeriod = 5 * time.Minute
DefaultSecretResyncPeriod is how often the data plane's secrets are synced when no Secret changes: what releases the virtual IP of a host no secret is restricted to any more once its retention is over, and repairs maps that drifted.
Variables ¶
This section is empty.
Functions ¶
func TrustedDNSServers ¶ added in v0.3.0
func TrustedDNSServers(ctx context.Context, reader client.Reader, static []net.IP, log *zap.SugaredLogger) []net.IP
TrustedDNSServers returns the DNS servers whose answers the data plane believes: kube-dns's ClusterIPs (both of a dual-stack Service, which pods are given both of as nameservers), the addresses of its endpoints, and static (--trusted-dns-servers). The endpoints are where answers come from when the CNI load balances Services at the socket (Cilium's kube-proxy replacement): the pod's query goes to a CoreDNS pod directly, and so the answer comes back from its address, not from the ClusterIP. A failed read leaves its addresses out.
Types ¶
type Container ¶ added in v0.3.0
Container is a container the container runtime is about to start, as it reports it over NRI.
type NRIPlugin ¶ added in v0.3.0
type NRIPlugin struct {
Preparer Preparer
SocketPath string
// HostRoot is the host's root filesystem as this process sees it: the
// runtime reports network namespace paths in the host's mount
// namespace. "" means /proc/1/root (with hostPID).
HostRoot string
Log *zap.SugaredLogger
// Reconnect delays: after the runtime's connection closed, and while no
// runtime serves NRI at SocketPath. Zero means the defaults.
RetryAfterClose time.Duration
// contains filtered or unexported fields
}
NRIPlugin hooks kloak into the container runtime through NRI (the Node Resource Interface of containerd and CRI-O). The runtime calls it while it creates each pod sandbox, and again before it creates and before it starts each container, and waits for it. Kloak attaches the virtual IP DNS rewrite while the sandbox is created (PrepareSandbox), before any container of the pod resolves a name, and a container's TLS uprobes before it starts (PrepareContainer), so that its first TLS write is rewritten. Without NRI (a runtime without it, NRI disabled, or the socket not mounted), the Reconciler attaches the rewrite by polling Pending pods, and the uprobes once it sees a container running.
The plugin never fails a runtime request: an error would fail the pod's sandbox or container. A request taking longer than the runtime's timeout (2 s by default) disconnects the plugin, which reconnects.
type Preparer ¶ added in v0.3.0
type Preparer interface {
PrepareSandbox(ctx context.Context, sb *Sandbox) bool
PrepareContainer(ctx context.Context, sb *Sandbox, c *Container)
}
Preparer prepares what the container runtime creates: a pod sandbox (Reconciler.PrepareSandbox), and each container before it starts (Reconciler.PrepareContainer).
type Reconciler ¶
type Reconciler struct {
client.Client
Log *zap.SugaredLogger
Scheme *runtime.Scheme
UprobeManager *ebpf.TLSUprobeManager
CgroupRoot string
// NodeName filters pods to only those on this node (empty = all nodes)
NodeName string
// APIReader reads a pod from the API server when the cache does not have
// it yet (PrepareSandbox); nil: cache only.
APIReader client.Reader
// contains filtered or unexported fields
}
Reconciler watches pods and manages eBPF cgroup tracking.
func NewReconciler ¶
func NewReconciler(c client.Client, log *zap.SugaredLogger, scheme *runtime.Scheme, uprobeMgr *ebpf.TLSUprobeManager, cgroupRoot, nodeName string) *Reconciler
NewReconciler creates a new pod reconciler.
func (*Reconciler) GetTrackedPodCount ¶
func (r *Reconciler) GetTrackedPodCount() int
GetTrackedPodCount returns the number of currently tracked pods.
func (*Reconciler) PrepareContainer ¶ added in v0.3.0
func (r *Reconciler) PrepareContainer(ctx context.Context, sb *Sandbox, c *Container)
PrepareContainer attaches the TLS uprobes for a container of a kloak pod that the container runtime is about to start (NRI). The runtime waits for it: the container's process exists, in the container's cgroup, but has not run the container's command, so the command's first TLS write is rewritten. It tracks the container (for exec events, on which the command's executable is attached: the TLS linked into a Go or Bun binary, say), binds the pod's secrets to it, and attaches the TLS libraries in its filesystem, which its processes go through (the command's, and those it starts), and the pod's tc patch program.
It returns within containerPrepareTimeout: an attach that takes longer goes on in the background while the container starts. One that fails is retried by the reconciler, which attaches the container once the pod's status reports it running, as it does without NRI.
func (*Reconciler) PrepareSandbox ¶ added in v0.3.0
func (r *Reconciler) PrepareSandbox(ctx context.Context, sb *Sandbox) bool
PrepareSandbox attaches the virtual IP DNS rewrite in a kloak pod's network namespace and binds the pod at its addresses, while the container runtime creates the pod's sandbox or one of its containers (NRI): the runtime waits for it, so the rewrite is in place before any container of the pod resolves a name. It reports whether the pod is prepared; when it is not (no NRI, or a failure), the reconciler attaches the rewrite by polling the Pending pod, which leaves a short window at pod start.
func (*Reconciler) SetupWithManager ¶
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error
SetupWithManager sets up the controller with the Manager.
type Sandbox ¶ added in v0.3.0
type Sandbox struct {
ID string
UID string
Namespace string
Name string
// Annotations are the pod's (the kubelet passes them to the sandbox).
Annotations map[string]string
// NetnsPath is the sandbox's network namespace as a path this process
// can open; "" when the runtime does not report one (host network).
NetnsPath string
// IPs are the pod's addresses, when the runtime reports them.
IPs []netip.Addr
}
Sandbox is a pod sandbox the container runtime is creating, as it reports it over NRI.
type SecretReconciler ¶
SecretReconciler reconciles a Secret object
func (*SecretReconciler) SetupWithManager ¶
func (r *SecretReconciler) SetupWithManager(mgr ctrl.Manager) error
type SecretSyncReconciler ¶ added in v0.3.0
type SecretSyncReconciler struct {
// Sync makes the data plane hold the cluster's current secrets
// (TLSUprobeManager.SyncSecrets). An error is logged by the controller
// and retried with backoff.
Sync func(context.Context) error
// ResyncPeriod is the time between syncs when nothing changes;
// 0 means DefaultSecretResyncPeriod.
ResyncPeriod time.Duration
}
SecretSyncReconciler keeps the data plane's secrets in step with the cluster's kloak Secrets: an enabled Secret or a shadow that is created, changed or deleted triggers a sync.
func (*SecretSyncReconciler) Reconcile ¶ added in v0.3.0
Reconcile syncs every secret. Every request is secretSyncRequest.
func (*SecretSyncReconciler) SetupWithManager ¶ added in v0.3.0
func (r *SecretSyncReconciler) SetupWithManager(mgr ctrl.Manager) error
SetupWithManager watches Secrets, through the cache the Secret reconciler already fills, and syncs once at start: with no kloak Secret there is no event, and the virtual IPs restored from the pinned maps still need to be retired.
type TrustedDNSReconciler ¶ added in v0.3.0
type TrustedDNSReconciler struct {
client.Client
// Static are the --trusted-dns-servers.
Static []net.IP
// Apply makes the data plane trust exactly these servers.
Apply func([]net.IP) error
Log *zap.SugaredLogger
// contains filtered or unexported fields
}
TrustedDNSReconciler keeps the trusted DNS servers (TrustedDNSServers) in the data plane as kube-dns changes: its endpoints come and go with the CoreDNS pods.
func (*TrustedDNSReconciler) Reconcile ¶ added in v0.3.0
Reconcile recomputes the trusted servers and applies them when they changed. Every request names kube-dns.
func (*TrustedDNSReconciler) SetupWithManager ¶ added in v0.3.0
func (r *TrustedDNSReconciler) SetupWithManager(mgr ctrl.Manager) error
SetupWithManager watches the kube-dns Service and its EndpointSlices.