admission/exec: externalize exec admission controller

This commit is contained in:
Marko Mudrinić
2018-08-24 16:47:21 +02:00
parent 963adda7f9
commit b622acf8ec
3 changed files with 61 additions and 67 deletions

View File

@@ -20,11 +20,11 @@ import (
"fmt"
"io"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/admission"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/client-go/kubernetes"
)
const (
@@ -52,7 +52,7 @@ func Register(plugins *admission.Plugins) {
// a pod using host based configurations.
type DenyExec struct {
*admission.Handler
client internalclientset.Interface
client kubernetes.Interface
// these flags control which items will be checked to deny exec/attach
hostNetwork bool
@@ -62,20 +62,7 @@ type DenyExec struct {
}
var _ admission.ValidationInterface = &DenyExec{}
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&DenyExec{})
// NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod
// using host based configurations.
func NewDenyEscalatingExec() *DenyExec {
return &DenyExec{
Handler: admission.NewHandler(admission.Connect),
hostNetwork: true,
hostIPC: true,
hostPID: true,
privileged: true,
}
}
var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&DenyExec{})
// NewDenyExecOnPrivileged creates a new admission controller that is only checking the privileged
// option. This is for legacy support of the DenyExecOnPrivileged admission controller.
@@ -90,6 +77,31 @@ func NewDenyExecOnPrivileged() *DenyExec {
}
}
// NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod
// using host based configurations.
func NewDenyEscalatingExec() *DenyExec {
return &DenyExec{
Handler: admission.NewHandler(admission.Connect),
hostNetwork: true,
hostIPC: true,
hostPID: true,
privileged: true,
}
}
// SetExternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (d *DenyExec) SetExternalKubeClientSet(client kubernetes.Interface) {
d.client = client
}
// ValidateInitialization implements the InitializationValidator interface.
func (d *DenyExec) ValidateInitialization() error {
if d.client == nil {
return fmt.Errorf("missing client")
}
return nil
}
// Validate makes an admission decision based on the request attributes
func (d *DenyExec) Validate(a admission.Attributes) (err error) {
path := a.GetResource().Resource
@@ -100,24 +112,21 @@ func (d *DenyExec) Validate(a admission.Attributes) (err error) {
if path != "pods/exec" && path != "pods/attach" {
return nil
}
pod, err := d.client.Core().Pods(a.GetNamespace()).Get(a.GetName(), metav1.GetOptions{})
pod, err := d.client.CoreV1().Pods(a.GetNamespace()).Get(a.GetName(), metav1.GetOptions{})
if err != nil {
return admission.NewForbidden(a, err)
}
if pod.Spec.SecurityContext != nil {
securityContext := pod.Spec.SecurityContext
if d.hostNetwork && securityContext.HostNetwork {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host network"))
}
if d.hostNetwork && pod.Spec.HostNetwork {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host network"))
}
if d.hostPID && securityContext.HostPID {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host pid"))
}
if d.hostPID && pod.Spec.HostPID {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host pid"))
}
if d.hostIPC && securityContext.HostIPC {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host ipc"))
}
if d.hostIPC && pod.Spec.HostIPC {
return admission.NewForbidden(a, fmt.Errorf("cannot exec into or attach to a container using host ipc"))
}
if d.privileged && isPrivileged(pod) {
@@ -128,7 +137,7 @@ func (d *DenyExec) Validate(a admission.Attributes) (err error) {
}
// isPrivileged will return true a pod has any privileged containers
func isPrivileged(pod *api.Pod) bool {
func isPrivileged(pod *corev1.Pod) bool {
for _, c := range pod.Spec.InitContainers {
if c.SecurityContext == nil || c.SecurityContext.Privileged == nil {
continue
@@ -147,16 +156,3 @@ func isPrivileged(pod *api.Pod) bool {
}
return false
}
// SetInternalKubeClientSet implements the WantsInternalKubeClientSet interface.
func (d *DenyExec) SetInternalKubeClientSet(client internalclientset.Interface) {
d.client = client
}
// ValidateInitialization implements the InitializationValidator interface.
func (d *DenyExec) ValidateInitialization() error {
if d.client == nil {
return fmt.Errorf("missing client")
}
return nil
}