pid mode
This commit is contained in:
parent
f152b28d4e
commit
ed80c2b940
@ -12490,7 +12490,11 @@
|
|||||||
},
|
},
|
||||||
"hostNetwork": {
|
"hostNetwork": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Host networking requested for this pod. Uses the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false."
|
"description": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false."
|
||||||
|
},
|
||||||
|
"hostPID": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use the host's pid namespace. Optional: Default to false."
|
||||||
},
|
},
|
||||||
"imagePullSecrets": {
|
"imagePullSecrets": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -87,7 +87,7 @@ DNS_REPLICAS=1
|
|||||||
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# Optional: Enable/disable public IP assignment for minions.
|
# Optional: Enable/disable public IP assignment for minions.
|
||||||
# Important Note: disable only if you have setup a NAT instance for internet access and configured appropriate routes!
|
# Important Note: disable only if you have setup a NAT instance for internet access and configured appropriate routes!
|
||||||
|
@ -83,7 +83,7 @@ DNS_REPLICAS=1
|
|||||||
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# Optional: Enable/disable public IP assignment for minions.
|
# Optional: Enable/disable public IP assignment for minions.
|
||||||
# Important Note: disable only if you have setup a NAT instance for internet access and configured appropriate routes!
|
# Important Note: disable only if you have setup a NAT instance for internet access and configured appropriate routes!
|
||||||
|
@ -55,4 +55,4 @@ ENABLE_CLUSTER_MONITORING="${KUBE_ENABLE_CLUSTER_MONITORING:-influxdb}"
|
|||||||
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
@ -51,7 +51,7 @@ KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=${SERVICE_CLUSTER_IP_RANGE}"
|
|||||||
# to do admission control of resources into cluster.
|
# to do admission control of resources into cluster.
|
||||||
# Comma-delimited list of:
|
# Comma-delimited list of:
|
||||||
# LimitRanger, AlwaysDeny, SecurityContextDeny, NamespaceExists,
|
# LimitRanger, AlwaysDeny, SecurityContextDeny, NamespaceExists,
|
||||||
# NamespaceLifecycle, NamespaceAutoProvision, DenyExecOnPrivileged,
|
# NamespaceLifecycle, NamespaceAutoProvision, DenyEscalatingExec,
|
||||||
# AlwaysAdmit, ServiceAccount, ResourceQuota
|
# AlwaysAdmit, ServiceAccount, ResourceQuota
|
||||||
#KUBE_ADMISSION_CONTROL="--admission-control=\"${ADMISSION_CONTROL}\""
|
#KUBE_ADMISSION_CONTROL="--admission-control=\"${ADMISSION_CONTROL}\""
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ if [[ "${ENABLE_HORIZONTAL_POD_AUTOSCALER}" == "true" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# Optional: if set to true kube-up will automatically check for existing resources and clean them up.
|
# Optional: if set to true kube-up will automatically check for existing resources and clean them up.
|
||||||
KUBE_UP_AUTOMATIC_CLEANUP=${KUBE_UP_AUTOMATIC_CLEANUP:-false}
|
KUBE_UP_AUTOMATIC_CLEANUP=${KUBE_UP_AUTOMATIC_CLEANUP:-false}
|
||||||
|
@ -112,7 +112,7 @@ if [[ "${ENABLE_HORIZONTAL_POD_AUTOSCALER}" == "true" ]]; then
|
|||||||
ENABLE_EXPERIMENTAL_API=true
|
ENABLE_EXPERIMENTAL_API=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# Optional: if set to true kube-up will automatically check for existing resources and clean them up.
|
# Optional: if set to true kube-up will automatically check for existing resources and clean them up.
|
||||||
KUBE_UP_AUTOMATIC_CLEANUP=${KUBE_UP_AUTOMATIC_CLEANUP:-false}
|
KUBE_UP_AUTOMATIC_CLEANUP=${KUBE_UP_AUTOMATIC_CLEANUP:-false}
|
||||||
|
@ -89,7 +89,7 @@ apiserver:
|
|||||||
--external-hostname=apiserver
|
--external-hostname=apiserver
|
||||||
--etcd-servers=http://etcd:4001
|
--etcd-servers=http://etcd:4001
|
||||||
--port=8888
|
--port=8888
|
||||||
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
--authorization-mode=AlwaysAllow
|
--authorization-mode=AlwaysAllow
|
||||||
--token-auth-file=/var/run/kubernetes/auth/token-users
|
--token-auth-file=/var/run/kubernetes/auth/token-users
|
||||||
--basic-auth-file=/var/run/kubernetes/auth/basic-users
|
--basic-auth-file=/var/run/kubernetes/auth/basic-users
|
||||||
|
@ -35,7 +35,7 @@ export SERVICE_CLUSTER_IP_RANGE=${SERVICE_CLUSTER_IP_RANGE:-192.168.3.0/24} # f
|
|||||||
export FLANNEL_NET=${FLANNEL_NET:-172.16.0.0/16}
|
export FLANNEL_NET=${FLANNEL_NET:-172.16.0.0/16}
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
export ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,SecurityContextDeny
|
export ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,DenyEscalatingExec,SecurityContextDeny
|
||||||
|
|
||||||
SERVICE_NODE_PORT_RANGE=${SERVICE_NODE_PORT_RANGE:-"30000-32767"}
|
SERVICE_NODE_PORT_RANGE=${SERVICE_NODE_PORT_RANGE:-"30000-32767"}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ MASTER_USER=vagrant
|
|||||||
MASTER_PASSWD=vagrant
|
MASTER_PASSWD=vagrant
|
||||||
|
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# Optional: Enable node logging.
|
# Optional: Enable node logging.
|
||||||
ENABLE_NODE_LOGGING=false
|
ENABLE_NODE_LOGGING=false
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
// Admission policies
|
// Admission policies
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/admit"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/admit"
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/deny"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/deny"
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/exec/denyprivileged"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/exec"
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/initialresources"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/initialresources"
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/limitranger"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/limitranger"
|
||||||
_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/autoprovision"
|
_ "k8s.io/kubernetes/plugin/pkg/admission/namespace/autoprovision"
|
||||||
|
@ -293,6 +293,7 @@ func (s *APIServer) Run(_ []string) error {
|
|||||||
// TODO(vmarmol): Implement support for HostNetworkSources.
|
// TODO(vmarmol): Implement support for HostNetworkSources.
|
||||||
PrivilegedSources: capabilities.PrivilegedSources{
|
PrivilegedSources: capabilities.PrivilegedSources{
|
||||||
HostNetworkSources: []string{},
|
HostNetworkSources: []string{},
|
||||||
|
HostPIDSources: []string{},
|
||||||
},
|
},
|
||||||
PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec,
|
PerConnectionBandwidthLimitBytesPerSec: s.MaxConnectionBytesPerSec,
|
||||||
})
|
})
|
||||||
|
@ -93,6 +93,7 @@ type KubeletServer struct {
|
|||||||
HealthzPort int
|
HealthzPort int
|
||||||
HostnameOverride string
|
HostnameOverride string
|
||||||
HostNetworkSources string
|
HostNetworkSources string
|
||||||
|
HostPIDSources string
|
||||||
HTTPCheckFrequency time.Duration
|
HTTPCheckFrequency time.Duration
|
||||||
ImageGCHighThresholdPercent int
|
ImageGCHighThresholdPercent int
|
||||||
ImageGCLowThresholdPercent int
|
ImageGCLowThresholdPercent int
|
||||||
@ -170,6 +171,7 @@ func NewKubeletServer() *KubeletServer {
|
|||||||
HealthzBindAddress: net.ParseIP("127.0.0.1"),
|
HealthzBindAddress: net.ParseIP("127.0.0.1"),
|
||||||
HealthzPort: 10248,
|
HealthzPort: 10248,
|
||||||
HostNetworkSources: kubelet.FileSource,
|
HostNetworkSources: kubelet.FileSource,
|
||||||
|
HostPIDSources: kubelet.FileSource,
|
||||||
HTTPCheckFrequency: 20 * time.Second,
|
HTTPCheckFrequency: 20 * time.Second,
|
||||||
ImageGCHighThresholdPercent: 90,
|
ImageGCHighThresholdPercent: 90,
|
||||||
ImageGCLowThresholdPercent: 80,
|
ImageGCLowThresholdPercent: 80,
|
||||||
@ -222,6 +224,7 @@ func (s *KubeletServer) AddFlags(fs *pflag.FlagSet) {
|
|||||||
fs.StringVar(&s.RootDirectory, "root-dir", s.RootDirectory, "Directory path for managing kubelet files (volume mounts,etc).")
|
fs.StringVar(&s.RootDirectory, "root-dir", s.RootDirectory, "Directory path for managing kubelet files (volume mounts,etc).")
|
||||||
fs.BoolVar(&s.AllowPrivileged, "allow-privileged", s.AllowPrivileged, "If true, allow containers to request privileged mode. [default=false]")
|
fs.BoolVar(&s.AllowPrivileged, "allow-privileged", s.AllowPrivileged, "If true, allow containers to request privileged mode. [default=false]")
|
||||||
fs.StringVar(&s.HostNetworkSources, "host-network-sources", s.HostNetworkSources, "Comma-separated list of sources from which the Kubelet allows pods to use of host network. For all sources use \"*\" [default=\"file\"]")
|
fs.StringVar(&s.HostNetworkSources, "host-network-sources", s.HostNetworkSources, "Comma-separated list of sources from which the Kubelet allows pods to use of host network. For all sources use \"*\" [default=\"file\"]")
|
||||||
|
fs.StringVar(&s.HostPIDSources, "host-pid-sources", s.HostPIDSources, "Comma-separated list of sources from which the Kubelet allows pods to use the host pid namespace. For all sources use \"*\" [default=\"file\"]")
|
||||||
fs.Float64Var(&s.RegistryPullQPS, "registry-qps", s.RegistryPullQPS, "If > 0, limit registry pull QPS to this value. If 0, unlimited. [default=0.0]")
|
fs.Float64Var(&s.RegistryPullQPS, "registry-qps", s.RegistryPullQPS, "If > 0, limit registry pull QPS to this value. If 0, unlimited. [default=0.0]")
|
||||||
fs.IntVar(&s.RegistryBurst, "registry-burst", s.RegistryBurst, "Maximum size of a bursty pulls, temporarily allows pulls to burst to this number, while still not exceeding registry-qps. Only used if --registry-qps > 0")
|
fs.IntVar(&s.RegistryBurst, "registry-burst", s.RegistryBurst, "Maximum size of a bursty pulls, temporarily allows pulls to burst to this number, while still not exceeding registry-qps. Only used if --registry-qps > 0")
|
||||||
fs.Float32Var(&s.EventRecordQPS, "event-qps", s.EventRecordQPS, "If > 0, limit event creations per second to this value. If 0, unlimited. [default=0.0]")
|
fs.Float32Var(&s.EventRecordQPS, "event-qps", s.EventRecordQPS, "If > 0, limit event creations per second to this value. If 0, unlimited. [default=0.0]")
|
||||||
@ -278,6 +281,11 @@ func (s *KubeletServer) KubeletConfig() (*KubeletConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostPIDSources, err := kubelet.GetValidatedSources(strings.Split(s.HostPIDSources, ","))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
mounter := mount.New()
|
mounter := mount.New()
|
||||||
if s.Containerized {
|
if s.Containerized {
|
||||||
glog.V(2).Info("Running kubelet in containerized mode (experimental)")
|
glog.V(2).Info("Running kubelet in containerized mode (experimental)")
|
||||||
@ -342,6 +350,7 @@ func (s *KubeletServer) KubeletConfig() (*KubeletConfig, error) {
|
|||||||
FileCheckFrequency: s.FileCheckFrequency,
|
FileCheckFrequency: s.FileCheckFrequency,
|
||||||
HostnameOverride: s.HostnameOverride,
|
HostnameOverride: s.HostnameOverride,
|
||||||
HostNetworkSources: hostNetworkSources,
|
HostNetworkSources: hostNetworkSources,
|
||||||
|
HostPIDSources: hostPIDSources,
|
||||||
HTTPCheckFrequency: s.HTTPCheckFrequency,
|
HTTPCheckFrequency: s.HTTPCheckFrequency,
|
||||||
ImageGCPolicy: imageGCPolicy,
|
ImageGCPolicy: imageGCPolicy,
|
||||||
KubeClient: nil,
|
KubeClient: nil,
|
||||||
@ -673,6 +682,7 @@ func RunKubelet(kcfg *KubeletConfig, builder KubeletBuilder) error {
|
|||||||
|
|
||||||
privilegedSources := capabilities.PrivilegedSources{
|
privilegedSources := capabilities.PrivilegedSources{
|
||||||
HostNetworkSources: kcfg.HostNetworkSources,
|
HostNetworkSources: kcfg.HostNetworkSources,
|
||||||
|
HostPIDSources: kcfg.HostPIDSources,
|
||||||
}
|
}
|
||||||
capabilities.Setup(kcfg.AllowPrivileged, privilegedSources, 0)
|
capabilities.Setup(kcfg.AllowPrivileged, privilegedSources, 0)
|
||||||
|
|
||||||
@ -766,6 +776,7 @@ type KubeletConfig struct {
|
|||||||
Hostname string
|
Hostname string
|
||||||
HostnameOverride string
|
HostnameOverride string
|
||||||
HostNetworkSources []string
|
HostNetworkSources []string
|
||||||
|
HostPIDSources []string
|
||||||
HTTPCheckFrequency time.Duration
|
HTTPCheckFrequency time.Duration
|
||||||
ImageGCPolicy kubelet.ImageGCPolicy
|
ImageGCPolicy kubelet.ImageGCPolicy
|
||||||
KubeClient *client.Client
|
KubeClient *client.Client
|
||||||
|
@ -43,7 +43,8 @@ Documentation for other releases can be found at
|
|||||||
- [What does each plug-in do?](#what-does-each-plug-in-do)
|
- [What does each plug-in do?](#what-does-each-plug-in-do)
|
||||||
- [AlwaysAdmit](#alwaysadmit)
|
- [AlwaysAdmit](#alwaysadmit)
|
||||||
- [AlwaysDeny](#alwaysdeny)
|
- [AlwaysDeny](#alwaysdeny)
|
||||||
- [DenyExecOnPrivileged](#denyexeconprivileged)
|
- [DenyExecOnPrivileged (deprecated)](#denyexeconprivileged-deprecated)
|
||||||
|
- [DenyEscalatingExec](#denyescalatingexec)
|
||||||
- [ServiceAccount](#serviceaccount)
|
- [ServiceAccount](#serviceaccount)
|
||||||
- [SecurityContextDeny](#securitycontextdeny)
|
- [SecurityContextDeny](#securitycontextdeny)
|
||||||
- [ResourceQuota](#resourcequota)
|
- [ResourceQuota](#resourcequota)
|
||||||
@ -92,13 +93,25 @@ Use this plugin by itself to pass-through all requests.
|
|||||||
|
|
||||||
Rejects all requests. Used for testing.
|
Rejects all requests. Used for testing.
|
||||||
|
|
||||||
### DenyExecOnPrivileged
|
### DenyExecOnPrivileged (deprecated)
|
||||||
|
|
||||||
This plug-in will intercept all requests to exec a command in a pod if that pod has a privileged container.
|
This plug-in will intercept all requests to exec a command in a pod if that pod has a privileged container.
|
||||||
|
|
||||||
If your cluster supports privileged containers, and you want to restrict the ability of end-users to exec
|
If your cluster supports privileged containers, and you want to restrict the ability of end-users to exec
|
||||||
commands in those containers, we strongly encourage enabling this plug-in.
|
commands in those containers, we strongly encourage enabling this plug-in.
|
||||||
|
|
||||||
|
This functionality has been merged into [DenyEscalatingExec](#denyescalatingexec).
|
||||||
|
|
||||||
|
### DenyEscalatingExec
|
||||||
|
|
||||||
|
This plug-in will deny exec and attach commands to pods that run with escalated privileges that
|
||||||
|
allow host access. This includes pods that run as privileged, have access to the host IPC namespace, and
|
||||||
|
have access to the host PID namespace.
|
||||||
|
|
||||||
|
If your cluster supports containers that run with escalated privileges, and you want to
|
||||||
|
restrict the ability of end-users to exec commands in those containers, we strongly encourage
|
||||||
|
enabling this plug-in.
|
||||||
|
|
||||||
### ServiceAccount
|
### ServiceAccount
|
||||||
|
|
||||||
This plug-in implements automation for [serviceAccounts](../user-guide/service-accounts.md).
|
This plug-in implements automation for [serviceAccounts](../user-guide/service-accounts.md).
|
||||||
@ -159,7 +172,7 @@ Yes.
|
|||||||
For Kubernetes 1.0, we strongly recommend running the following set of admission control plug-ins (order matters):
|
For Kubernetes 1.0, we strongly recommend running the following set of admission control plug-ins (order matters):
|
||||||
|
|
||||||
```
|
```
|
||||||
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ spec:
|
|||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
- /usr/local/bin/kube-apiserver --address=127.0.0.1 --etcd-servers=http://127.0.0.1:4001
|
- /usr/local/bin/kube-apiserver --address=127.0.0.1 --etcd-servers=http://127.0.0.1:4001
|
||||||
--cloud-provider=gce --admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
--cloud-provider=gce --admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
--service-cluster-ip-range=10.0.0.0/16 --client-ca-file=/srv/kubernetes/ca.crt
|
--service-cluster-ip-range=10.0.0.0/16 --client-ca-file=/srv/kubernetes/ca.crt
|
||||||
--basic-auth-file=/srv/kubernetes/basic_auth.csv --cluster-name=e2e-test-bburns
|
--basic-auth-file=/srv/kubernetes/basic_auth.csv --cluster-name=e2e-test-bburns
|
||||||
--tls-cert-file=/srv/kubernetes/server.cert --tls-private-key-file=/srv/kubernetes/server.key
|
--tls-cert-file=/srv/kubernetes/server.cert --tls-private-key-file=/srv/kubernetes/server.key
|
||||||
|
@ -48,7 +48,7 @@ cluster's shared state through which all other components interact.
|
|||||||
|
|
||||||
```
|
```
|
||||||
--address=<nil>: DEPRECATED: see --insecure-bind-address instead
|
--address=<nil>: DEPRECATED: see --insecure-bind-address instead
|
||||||
--admission-control="": Ordered list of plug-ins to do admission control of resources into cluster. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, DenyExecOnPrivileged, LimitRanger, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, ResourceQuota, SecurityContextDeny, ServiceAccount
|
--admission-control="": Ordered list of plug-ins to do admission control of resources into cluster. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, DenyExecOnPrivileged, DenyEscalatingExec, LimitRanger, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, ResourceQuota, SecurityContextDeny, ServiceAccount
|
||||||
--admission-control-config-file="": File with admission control configuration.
|
--admission-control-config-file="": File with admission control configuration.
|
||||||
--advertise-address=<nil>: The IP address on which to advertise the apiserver to members of the cluster. This address must be reachable by the rest of the cluster. If blank, the --bind-address will be used. If --bind-address is unspecified, the host's default interface will be used.
|
--advertise-address=<nil>: The IP address on which to advertise the apiserver to members of the cluster. This address must be reachable by the rest of the cluster. If blank, the --bind-address will be used. If --bind-address is unspecified, the host's default interface will be used.
|
||||||
--allow-privileged=false: If true, allow privileged containers.
|
--allow-privileged=false: If true, allow privileged containers.
|
||||||
|
@ -84,6 +84,7 @@ HTTP server: The kubelet can also listen for HTTP and respond to a simple API
|
|||||||
--healthz-port=0: The port of the localhost healthz endpoint
|
--healthz-port=0: The port of the localhost healthz endpoint
|
||||||
-h, --help=false: help for kubelet
|
-h, --help=false: help for kubelet
|
||||||
--host-network-sources="": Comma-separated list of sources from which the Kubelet allows pods to use of host network. For all sources use "*" [default="file"]
|
--host-network-sources="": Comma-separated list of sources from which the Kubelet allows pods to use of host network. For all sources use "*" [default="file"]
|
||||||
|
--host-pid-sources="": Comma-separated list of sources from which the Kubelet allows pods to use the host pid namespace. For all sources use "*" [default="file"]
|
||||||
--hostname-override="": If non-empty, will use this string as identification instead of the actual hostname.
|
--hostname-override="": If non-empty, will use this string as identification instead of the actual hostname.
|
||||||
--http-check-frequency=0: Duration between checking http for new data
|
--http-check-frequency=0: Duration between checking http for new data
|
||||||
--image-gc-high-threshold=0: The percent of disk usage after which image garbage collection is always run. Default: 90%%
|
--image-gc-high-threshold=0: The percent of disk usage after which image garbage collection is always run. Default: 90%%
|
||||||
|
@ -89,7 +89,7 @@ coreos:
|
|||||||
ExecStart=/opt/bin/kube-apiserver \
|
ExecStart=/opt/bin/kube-apiserver \
|
||||||
--service-account-key-file=/opt/bin/kube-serviceaccount.key \
|
--service-account-key-file=/opt/bin/kube-serviceaccount.key \
|
||||||
--service-account-lookup=false \
|
--service-account-lookup=false \
|
||||||
--admission-control=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota \
|
--admission-control=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota \
|
||||||
--runtime-config=api/v1 \
|
--runtime-config=api/v1 \
|
||||||
--allow-privileged=true \
|
--allow-privileged=true \
|
||||||
--insecure-bind-address=0.0.0.0 \
|
--insecure-bind-address=0.0.0.0 \
|
||||||
|
@ -201,7 +201,7 @@ function set_service_accounts {
|
|||||||
|
|
||||||
function start_apiserver {
|
function start_apiserver {
|
||||||
# Admission Controllers to invoke prior to persisting objects in cluster
|
# Admission Controllers to invoke prior to persisting objects in cluster
|
||||||
ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
ADMISSION_CONTROL=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,DenyEscalatingExec,ResourceQuota
|
||||||
|
|
||||||
# This is the default dir and filename where the apiserver will generate a self-signed cert
|
# This is the default dir and filename where the apiserver will generate a self-signed cert
|
||||||
# which should be able to be used as the CA to verify itself
|
# which should be able to be used as the CA to verify itself
|
||||||
|
@ -103,6 +103,7 @@ healthz-port
|
|||||||
horizontal-pod-autoscaler-sync-period
|
horizontal-pod-autoscaler-sync-period
|
||||||
hostname-override
|
hostname-override
|
||||||
host-network-sources
|
host-network-sources
|
||||||
|
host-pid-sources
|
||||||
http-check-frequency
|
http-check-frequency
|
||||||
http-port
|
http-port
|
||||||
ignore-not-found
|
ignore-not-found
|
||||||
|
@ -1431,6 +1431,7 @@ func deepCopy_api_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error
|
|||||||
out.ServiceAccountName = in.ServiceAccountName
|
out.ServiceAccountName = in.ServiceAccountName
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -980,10 +980,13 @@ type PodSpec struct {
|
|||||||
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
|
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
|
||||||
// requirements.
|
// requirements.
|
||||||
NodeName string `json:"nodeName,omitempty"`
|
NodeName string `json:"nodeName,omitempty"`
|
||||||
// Uses the host's network namespace. If this option is set, the ports that will be
|
// Use the host's network namespace. If this option is set, the ports that will be
|
||||||
// used must be specified.
|
// used must be specified.
|
||||||
// Optional: Default to false.
|
// Optional: Default to false.
|
||||||
HostNetwork bool `json:"hostNetwork,omitempty"`
|
HostNetwork bool `json:"hostNetwork,omitempty"`
|
||||||
|
// Use the host's pid namespace.
|
||||||
|
// Optional: Default to false.
|
||||||
|
HostPID bool `json:"hostPID,omitempty"`
|
||||||
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
|
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
|
||||||
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
|
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
|
||||||
// in the case of docker, only DockerConfig type secrets are honored.
|
// in the case of docker, only DockerConfig type secrets are honored.
|
||||||
|
@ -282,6 +282,7 @@ func convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *PodSpec, s conversi
|
|||||||
out.DeprecatedServiceAccount = in.ServiceAccountName
|
out.DeprecatedServiceAccount = in.ServiceAccountName
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
@ -349,6 +350,7 @@ func convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversi
|
|||||||
}
|
}
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -1431,6 +1431,7 @@ func deepCopy_v1_PodSpec(in PodSpec, out *PodSpec, c *conversion.Cloner) error {
|
|||||||
out.DeprecatedServiceAccount = in.DeprecatedServiceAccount
|
out.DeprecatedServiceAccount = in.DeprecatedServiceAccount
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -1227,10 +1227,13 @@ type PodSpec struct {
|
|||||||
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
|
// the scheduler simply schedules this pod onto that node, assuming that it fits resource
|
||||||
// requirements.
|
// requirements.
|
||||||
NodeName string `json:"nodeName,omitempty"`
|
NodeName string `json:"nodeName,omitempty"`
|
||||||
// Host networking requested for this pod. Uses the host's network namespace.
|
// Host networking requested for this pod. Use the host's network namespace.
|
||||||
// If this option is set, the ports that will be used must be specified.
|
// If this option is set, the ports that will be used must be specified.
|
||||||
// Default to false.
|
// Default to false.
|
||||||
HostNetwork bool `json:"hostNetwork,omitempty"`
|
HostNetwork bool `json:"hostNetwork,omitempty"`
|
||||||
|
// Use the host's pid namespace.
|
||||||
|
// Optional: Default to false.
|
||||||
|
HostPID bool `json:"hostPID,omitempty"`
|
||||||
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
|
// ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.
|
||||||
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
|
// If specified, these secrets will be passed to individual puller implementations for them to use. For example,
|
||||||
// in the case of docker, only DockerConfig type secrets are honored.
|
// in the case of docker, only DockerConfig type secrets are honored.
|
||||||
|
@ -953,7 +953,8 @@ var map_PodSpec = map[string]string{
|
|||||||
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
|
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
|
||||||
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",
|
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",
|
||||||
"nodeName": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
|
"nodeName": "NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements.",
|
||||||
"hostNetwork": "Host networking requested for this pod. Uses the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
|
"hostNetwork": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
|
||||||
|
"hostPID": "Use the host's pid namespace. Optional: Default to false.",
|
||||||
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod",
|
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#specifying-imagepullsecrets-on-a-pod",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,6 +465,7 @@ func deepCopy_api_PodSpec(in api.PodSpec, out *api.PodSpec, c *conversion.Cloner
|
|||||||
out.ServiceAccountName = in.ServiceAccountName
|
out.ServiceAccountName = in.ServiceAccountName
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -98,6 +98,7 @@ func convert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *v1.PodSpec, s conve
|
|||||||
out.DeprecatedServiceAccount = in.ServiceAccountName
|
out.DeprecatedServiceAccount = in.ServiceAccountName
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
@ -165,6 +166,7 @@ func convert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s conve
|
|||||||
}
|
}
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]api.LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -483,6 +483,7 @@ func deepCopy_v1_PodSpec(in v1.PodSpec, out *v1.PodSpec, c *conversion.Cloner) e
|
|||||||
out.DeprecatedServiceAccount = in.DeprecatedServiceAccount
|
out.DeprecatedServiceAccount = in.DeprecatedServiceAccount
|
||||||
out.NodeName = in.NodeName
|
out.NodeName = in.NodeName
|
||||||
out.HostNetwork = in.HostNetwork
|
out.HostNetwork = in.HostNetwork
|
||||||
|
out.HostPID = in.HostPID
|
||||||
if in.ImagePullSecrets != nil {
|
if in.ImagePullSecrets != nil {
|
||||||
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
|
out.ImagePullSecrets = make([]v1.LocalObjectReference, len(in.ImagePullSecrets))
|
||||||
for i := range in.ImagePullSecrets {
|
for i := range in.ImagePullSecrets {
|
||||||
|
@ -38,6 +38,9 @@ type Capabilities struct {
|
|||||||
type PrivilegedSources struct {
|
type PrivilegedSources struct {
|
||||||
// List of pod sources for which using host network is allowed.
|
// List of pod sources for which using host network is allowed.
|
||||||
HostNetworkSources []string
|
HostNetworkSources []string
|
||||||
|
|
||||||
|
// List of pod sources for which using host pid namespace is allowed.
|
||||||
|
HostPIDSources []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Clean these up into a singleton
|
// TODO: Clean these up into a singleton
|
||||||
@ -79,6 +82,7 @@ func Get() Capabilities {
|
|||||||
AllowPrivileged: false,
|
AllowPrivileged: false,
|
||||||
PrivilegedSources: PrivilegedSources{
|
PrivilegedSources: PrivilegedSources{
|
||||||
HostNetworkSources: []string{},
|
HostNetworkSources: []string{},
|
||||||
|
HostPIDSources: []string{},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,8 @@ func (dm *DockerManager) runContainer(
|
|||||||
ref *api.ObjectReference,
|
ref *api.ObjectReference,
|
||||||
netMode string,
|
netMode string,
|
||||||
ipcMode string,
|
ipcMode string,
|
||||||
utsMode string) (string, error) {
|
utsMode string,
|
||||||
|
pidMode string) (string, error) {
|
||||||
|
|
||||||
dockerName := KubeletContainerName{
|
dockerName := KubeletContainerName{
|
||||||
PodFullName: kubecontainer.GetPodFullName(pod),
|
PodFullName: kubecontainer.GetPodFullName(pod),
|
||||||
@ -720,6 +721,7 @@ func (dm *DockerManager) runContainer(
|
|||||||
NetworkMode: netMode,
|
NetworkMode: netMode,
|
||||||
IpcMode: ipcMode,
|
IpcMode: ipcMode,
|
||||||
UTSMode: utsMode,
|
UTSMode: utsMode,
|
||||||
|
PidMode: pidMode,
|
||||||
// Memory and CPU are set here for newer versions of Docker (1.6+).
|
// Memory and CPU are set here for newer versions of Docker (1.6+).
|
||||||
Memory: memoryLimit,
|
Memory: memoryLimit,
|
||||||
MemorySwap: -1,
|
MemorySwap: -1,
|
||||||
@ -1368,7 +1370,7 @@ func containerAndPodFromLabels(inspect *docker.Container) (pod *api.Pod, contain
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run a single container from a pod. Returns the docker container ID
|
// Run a single container from a pod. Returns the docker container ID
|
||||||
func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Container, netMode, ipcMode string) (kubeletTypes.DockerID, error) {
|
func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Container, netMode, ipcMode string, pidMode string) (kubeletTypes.DockerID, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
defer func() {
|
defer func() {
|
||||||
metrics.ContainerManagerLatency.WithLabelValues("runContainerInPod").Observe(metrics.SinceInMicroseconds(start))
|
metrics.ContainerManagerLatency.WithLabelValues("runContainerInPod").Observe(metrics.SinceInMicroseconds(start))
|
||||||
@ -1388,7 +1390,7 @@ func (dm *DockerManager) runContainerInPod(pod *api.Pod, container *api.Containe
|
|||||||
if pod.Spec.HostNetwork {
|
if pod.Spec.HostNetwork {
|
||||||
utsMode = "host"
|
utsMode = "host"
|
||||||
}
|
}
|
||||||
id, err := dm.runContainer(pod, container, opts, ref, netMode, ipcMode, utsMode)
|
id, err := dm.runContainer(pod, container, opts, ref, netMode, ipcMode, utsMode, pidMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -1520,7 +1522,7 @@ func (dm *DockerManager) createPodInfraContainer(pod *api.Pod) (kubeletTypes.Doc
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
id, err := dm.runContainerInPod(pod, container, netNamespace, "")
|
id, err := dm.runContainerInPod(pod, container, netNamespace, "", getPidMode(pod))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -1776,7 +1778,7 @@ func (dm *DockerManager) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, pod
|
|||||||
|
|
||||||
// TODO(dawnchen): Check RestartPolicy.DelaySeconds before restart a container
|
// TODO(dawnchen): Check RestartPolicy.DelaySeconds before restart a container
|
||||||
namespaceMode := fmt.Sprintf("container:%v", podInfraContainerID)
|
namespaceMode := fmt.Sprintf("container:%v", podInfraContainerID)
|
||||||
_, err = dm.runContainerInPod(pod, container, namespaceMode, namespaceMode)
|
_, err = dm.runContainerInPod(pod, container, namespaceMode, namespaceMode, getPidMode(pod))
|
||||||
dm.updateReasonCache(pod, container, err)
|
dm.updateReasonCache(pod, container, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(bburns) : Perhaps blacklist a container after N failures?
|
// TODO(bburns) : Perhaps blacklist a container after N failures?
|
||||||
@ -1889,3 +1891,12 @@ func (dm *DockerManager) doBackOff(pod *api.Pod, container *api.Container, podSt
|
|||||||
dm.clearReasonCache(pod, container)
|
dm.clearReasonCache(pod, container)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPidMode returns the pid mode to use on the docker container based on pod.Spec.HostPID.
|
||||||
|
func getPidMode(pod *api.Pod) string {
|
||||||
|
pidMode := ""
|
||||||
|
if pod.Spec.HostPID {
|
||||||
|
pidMode = "host"
|
||||||
|
}
|
||||||
|
return pidMode
|
||||||
|
}
|
||||||
|
@ -2335,3 +2335,20 @@ func TestGetUidFromUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetPidMode(t *testing.T) {
|
||||||
|
// test false
|
||||||
|
pod := &api.Pod{}
|
||||||
|
pidMode := getPidMode(pod)
|
||||||
|
|
||||||
|
if pidMode != "" {
|
||||||
|
t.Errorf("expected empty pid mode for pod but got %v", pidMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test true
|
||||||
|
pod.Spec.HostPID = true
|
||||||
|
pidMode = getPidMode(pod)
|
||||||
|
if pidMode != "host" {
|
||||||
|
t.Errorf("expected host pid mode for pod but got %v", pidMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -593,6 +593,8 @@ func (r *runtime) preparePod(pod *api.Pod, pullSecrets []api.Secret) (string, *k
|
|||||||
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false --private-net %s", r.rktBinAbsPath, uuid)
|
runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false --private-net %s", r.rktBinAbsPath, uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO handle pod.Spec.HostPID
|
||||||
|
|
||||||
units := []*unit.UnitOption{
|
units := []*unit.UnitOption{
|
||||||
newUnitOption(unitKubernetesSection, unitRktID, uuid),
|
newUnitOption(unitKubernetesSection, unitRktID, uuid),
|
||||||
newUnitOption(unitKubernetesSection, unitPodName, string(b)),
|
newUnitOption(unitKubernetesSection, unitPodName, string(b)),
|
||||||
|
@ -50,6 +50,16 @@ func canRunPod(pod *api.Pod) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pod.Spec.HostPID {
|
||||||
|
allowed, err := allowHostPID(pod)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !allowed {
|
||||||
|
return fmt.Errorf("pod with UID %q specified host PID, but is disallowed", pod.UID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !capabilities.Get().AllowPrivileged {
|
if !capabilities.Get().AllowPrivileged {
|
||||||
for _, container := range pod.Spec.Containers {
|
for _, container := range pod.Spec.Containers {
|
||||||
if securitycontext.HasPrivilegedRequest(&container) {
|
if securitycontext.HasPrivilegedRequest(&container) {
|
||||||
@ -73,3 +83,17 @@ func allowHostNetwork(pod *api.Pod) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determined whether the specified pod is allowed to use host networking
|
||||||
|
func allowHostPID(pod *api.Pod) (bool, error) {
|
||||||
|
podSource, err := getPodSource(pod)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, source := range capabilities.Get().PrivilegedSources.HostPIDSources {
|
||||||
|
if source == podSource {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package denyprivileged
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -28,19 +28,55 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
admission.RegisterPlugin("DenyEscalatingExec", func(client client.Interface, config io.Reader) (admission.Interface, error) {
|
||||||
|
return NewDenyEscalatingExec(client), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// This is for legacy support of the DenyExecOnPrivileged admission controller. Most
|
||||||
|
// of the time DenyEscalatingExec should be preferred.
|
||||||
admission.RegisterPlugin("DenyExecOnPrivileged", func(client client.Interface, config io.Reader) (admission.Interface, error) {
|
admission.RegisterPlugin("DenyExecOnPrivileged", func(client client.Interface, config io.Reader) (admission.Interface, error) {
|
||||||
return NewDenyExecOnPrivileged(client), nil
|
return NewDenyExecOnPrivileged(client), nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// denyExecOnPrivileged is an implementation of admission.Interface which says no to a pod/exec on
|
// denyExec is an implementation of admission.Interface which says no to a pod/exec on
|
||||||
// a privileged pod
|
// a pod using host based configurations.
|
||||||
type denyExecOnPrivileged struct {
|
type denyExec struct {
|
||||||
*admission.Handler
|
*admission.Handler
|
||||||
client client.Interface
|
client client.Interface
|
||||||
|
|
||||||
|
// these flags control which items will be checked to deny exec/attach
|
||||||
|
hostIPC bool
|
||||||
|
hostPID bool
|
||||||
|
privileged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *denyExecOnPrivileged) Admit(a admission.Attributes) (err error) {
|
// NewDenyEscalatingExec creates a new admission controller that denies an exec operation on a pod
|
||||||
|
// using host based configurations.
|
||||||
|
func NewDenyEscalatingExec(client client.Interface) admission.Interface {
|
||||||
|
return &denyExec{
|
||||||
|
Handler: admission.NewHandler(admission.Connect),
|
||||||
|
client: client,
|
||||||
|
hostIPC: true,
|
||||||
|
hostPID: true,
|
||||||
|
privileged: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDenyExecOnPrivileged creates a new admission controller that is only checking the privileged
|
||||||
|
// option. This is for legacy support of the DenyExecOnPrivileged admission controller. Most
|
||||||
|
// of the time NewDenyEscalatingExec should be preferred.
|
||||||
|
func NewDenyExecOnPrivileged(client client.Interface) admission.Interface {
|
||||||
|
return &denyExec{
|
||||||
|
Handler: admission.NewHandler(admission.Connect),
|
||||||
|
client: client,
|
||||||
|
hostIPC: false,
|
||||||
|
hostPID: false,
|
||||||
|
privileged: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *denyExec) Admit(a admission.Attributes) (err error) {
|
||||||
connectRequest, ok := a.GetObject().(*rest.ConnectRequest)
|
connectRequest, ok := a.GetObject().(*rest.ConnectRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.NewBadRequest("a connect request was received, but could not convert the request object.")
|
return errors.NewBadRequest("a connect request was received, but could not convert the request object.")
|
||||||
@ -53,9 +89,20 @@ func (d *denyExecOnPrivileged) Admit(a admission.Attributes) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return admission.NewForbidden(a, err)
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
if isPrivileged(pod) {
|
|
||||||
|
if d.hostPID && pod.Spec.HostPID {
|
||||||
|
return admission.NewForbidden(a, fmt.Errorf("Cannot exec into or attach to a container using host pid"))
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO uncomment when this feature lands https://github.com/kubernetes/kubernetes/pull/12470
|
||||||
|
// 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) {
|
||||||
return admission.NewForbidden(a, fmt.Errorf("Cannot exec into or attach to a privileged container"))
|
return admission.NewForbidden(a, fmt.Errorf("Cannot exec into or attach to a privileged container"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,11 +118,3 @@ func isPrivileged(pod *api.Pod) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDenyExecOnPrivileged creates a new admission controller that denies an exec operation on a privileged pod
|
|
||||||
func NewDenyExecOnPrivileged(client client.Interface) admission.Interface {
|
|
||||||
return &denyExecOnPrivileged{
|
|
||||||
Handler: admission.NewHandler(admission.Connect),
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
}
|
|
183
plugin/pkg/admission/exec/admission_test.go
Normal file
183
plugin/pkg/admission/exec/admission_test.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package exec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAdmission(t *testing.T) {
|
||||||
|
privPod := validPod("privileged")
|
||||||
|
priv := true
|
||||||
|
privPod.Spec.Containers[0].SecurityContext = &api.SecurityContext{
|
||||||
|
Privileged: &priv,
|
||||||
|
}
|
||||||
|
|
||||||
|
hostPIDPod := validPod("hostPID")
|
||||||
|
hostPIDPod.Spec.HostPID = true
|
||||||
|
|
||||||
|
// hostIPCPod := validPod("hostIPC")
|
||||||
|
// hostIPCPod.Spec.HostIPC = true
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
pod *api.Pod
|
||||||
|
shouldAccept bool
|
||||||
|
}{
|
||||||
|
"priv": {
|
||||||
|
shouldAccept: false,
|
||||||
|
pod: privPod,
|
||||||
|
},
|
||||||
|
"hostPID": {
|
||||||
|
shouldAccept: false,
|
||||||
|
pod: hostPIDPod,
|
||||||
|
},
|
||||||
|
// "hostIPC": {
|
||||||
|
// shouldAccept: false,
|
||||||
|
// pod: hostIPCPod,
|
||||||
|
// },
|
||||||
|
"non privileged": {
|
||||||
|
shouldAccept: true,
|
||||||
|
pod: validPod("nonPrivileged"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the same code as NewDenyEscalatingExec, using the direct object though to allow testAdmission to
|
||||||
|
// inject the client
|
||||||
|
handler := &denyExec{
|
||||||
|
Handler: admission.NewHandler(admission.Connect),
|
||||||
|
hostIPC: true,
|
||||||
|
hostPID: true,
|
||||||
|
privileged: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
testAdmission(t, tc.pod, handler, tc.shouldAccept)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run with a permissive config and all cases should pass
|
||||||
|
handler.privileged = false
|
||||||
|
handler.hostPID = false
|
||||||
|
handler.hostIPC = false
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
testAdmission(t, tc.pod, handler, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAdmission(t *testing.T, pod *api.Pod, handler *denyExec, shouldAccept bool) {
|
||||||
|
mockClient := &testclient.Fake{}
|
||||||
|
mockClient.AddReactor("get", "pods", func(action testclient.Action) (bool, runtime.Object, error) {
|
||||||
|
if action.(testclient.GetAction).GetName() == pod.Name {
|
||||||
|
return true, pod, nil
|
||||||
|
}
|
||||||
|
t.Errorf("Unexpected API call: %#v", action)
|
||||||
|
return true, nil, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
handler.client = mockClient
|
||||||
|
|
||||||
|
// pods/exec
|
||||||
|
{
|
||||||
|
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"}
|
||||||
|
err := handler.Admit(admission.NewAttributesRecord(req, "Pod", "test", "name", "pods", "exec", admission.Connect, nil))
|
||||||
|
if shouldAccept && err != nil {
|
||||||
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
|
}
|
||||||
|
if !shouldAccept && err == nil {
|
||||||
|
t.Errorf("An error was expected from the admission handler. Received nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pods/attach
|
||||||
|
{
|
||||||
|
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"}
|
||||||
|
err := handler.Admit(admission.NewAttributesRecord(req, "Pod", "test", "name", "pods", "attach", admission.Connect, nil))
|
||||||
|
if shouldAccept && err != nil {
|
||||||
|
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
||||||
|
}
|
||||||
|
if !shouldAccept && err == nil {
|
||||||
|
t.Errorf("An error was expected from the admission handler. Received nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test to ensure legacy admission controller works as expected.
|
||||||
|
func TestDenyExecOnPrivileged(t *testing.T) {
|
||||||
|
privPod := validPod("privileged")
|
||||||
|
priv := true
|
||||||
|
privPod.Spec.Containers[0].SecurityContext = &api.SecurityContext{
|
||||||
|
Privileged: &priv,
|
||||||
|
}
|
||||||
|
|
||||||
|
hostPIDPod := validPod("hostPID")
|
||||||
|
hostPIDPod.Spec.HostPID = true
|
||||||
|
|
||||||
|
// hostIPCPod := validPod("hostIPC")
|
||||||
|
// hostIPCPod.Spec.HostIPC = true
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
pod *api.Pod
|
||||||
|
shouldAccept bool
|
||||||
|
}{
|
||||||
|
"priv": {
|
||||||
|
shouldAccept: false,
|
||||||
|
pod: privPod,
|
||||||
|
},
|
||||||
|
"hostPID": {
|
||||||
|
shouldAccept: true,
|
||||||
|
pod: hostPIDPod,
|
||||||
|
},
|
||||||
|
// "hostIPC": {
|
||||||
|
// shouldAccept: true,
|
||||||
|
// pod: hostIPCPod,
|
||||||
|
// },
|
||||||
|
"non privileged": {
|
||||||
|
shouldAccept: true,
|
||||||
|
pod: validPod("nonPrivileged"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the same code as NewDenyExecOnPrivileged, using the direct object though to allow testAdmission to
|
||||||
|
// inject the client
|
||||||
|
handler := &denyExec{
|
||||||
|
Handler: admission.NewHandler(admission.Connect),
|
||||||
|
hostIPC: false,
|
||||||
|
hostPID: false,
|
||||||
|
privileged: true,
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
testAdmission(t, tc.pod, handler, tc.shouldAccept)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validPod(name string) *api.Pod {
|
||||||
|
return &api.Pod{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: name, Namespace: "test"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{Name: "ctr1", Image: "image"},
|
||||||
|
{Name: "ctr2", Image: "image2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package denyprivileged
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
"k8s.io/kubernetes/pkg/api/rest"
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
|
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestAdmission verifies a namespace is created on create requests for namespace managed resources
|
|
||||||
func TestAdmissionAccept(t *testing.T) {
|
|
||||||
testAdmission(t, acceptPod("podname"), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAdmissionDeny(t *testing.T) {
|
|
||||||
testAdmission(t, denyPod("podname"), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testAdmission(t *testing.T, pod *api.Pod, shouldAccept bool) {
|
|
||||||
mockClient := &testclient.Fake{}
|
|
||||||
mockClient.AddReactor("get", "pods", func(action testclient.Action) (bool, runtime.Object, error) {
|
|
||||||
if action.(testclient.GetAction).GetName() == pod.Name {
|
|
||||||
return true, pod, nil
|
|
||||||
}
|
|
||||||
t.Errorf("Unexpected API call: %#v", action)
|
|
||||||
return true, nil, nil
|
|
||||||
})
|
|
||||||
handler := &denyExecOnPrivileged{
|
|
||||||
client: mockClient,
|
|
||||||
}
|
|
||||||
|
|
||||||
// pods/exec
|
|
||||||
{
|
|
||||||
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/exec"}
|
|
||||||
err := handler.Admit(admission.NewAttributesRecord(req, "Pod", "test", "name", "pods", "exec", admission.Connect, nil))
|
|
||||||
if shouldAccept && err != nil {
|
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
|
||||||
}
|
|
||||||
if !shouldAccept && err == nil {
|
|
||||||
t.Errorf("An error was expected from the admission handler. Received nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pods/attach
|
|
||||||
{
|
|
||||||
req := &rest.ConnectRequest{Name: pod.Name, ResourcePath: "pods/attach"}
|
|
||||||
err := handler.Admit(admission.NewAttributesRecord(req, "Pod", "test", "name", "pods", "attach", admission.Connect, nil))
|
|
||||||
if shouldAccept && err != nil {
|
|
||||||
t.Errorf("Unexpected error returned from admission handler: %v", err)
|
|
||||||
}
|
|
||||||
if !shouldAccept && err == nil {
|
|
||||||
t.Errorf("An error was expected from the admission handler. Received nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func acceptPod(name string) *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: name, Namespace: "test"},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{Name: "ctr1", Image: "image"},
|
|
||||||
{Name: "ctr2", Image: "image2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func denyPod(name string) *api.Pod {
|
|
||||||
privileged := true
|
|
||||||
return &api.Pod{
|
|
||||||
ObjectMeta: api.ObjectMeta{Name: name, Namespace: "test"},
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{Name: "ctr1", Image: "image"},
|
|
||||||
{
|
|
||||||
Name: "ctr2",
|
|
||||||
Image: "image2",
|
|
||||||
SecurityContext: &api.SecurityContext{
|
|
||||||
Privileged: &privileged,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user