Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- derekwaynecarr
|
||||
- mikedanese
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Accessing the API"
|
||||
weight: 30
|
||||
---
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
reviewers:
|
||||
- bgrant0607
|
||||
- erictune
|
||||
- lavalamp
|
||||
title: Controlling Access to the Kubernetes API
|
||||
---
|
||||
|
||||
Users [access the API](/docs/user-guide/accessing-the-cluster) using `kubectl`,
|
||||
client libraries, or by making REST requests. Both human users and
|
||||
[Kubernetes service accounts](/docs/tasks/configure-pod-container/configure-service-account/) can be
|
||||
authorized for API access.
|
||||
When a request reaches the API, it goes through several stages, illustrated in the
|
||||
following diagram:
|
||||
|
||||

|
||||
|
||||
## Transport Security
|
||||
|
||||
In a typical Kubernetes cluster, the API serves on port 443.
|
||||
The API server presents a certificate. This certificate is
|
||||
often self-signed, so `$USER/.kube/config` on the user's machine typically
|
||||
contains the root certificate for the API server's certificate, which when specified
|
||||
is used in place of the system default root certificate. This certificate is typically
|
||||
automatically written into your `$USER/.kube/config` when you create a cluster yourself
|
||||
using `kube-up.sh`. If the cluster has multiple users, then the creator needs to share
|
||||
the certificate with other users.
|
||||
|
||||
## Authentication
|
||||
|
||||
Once TLS is established, the HTTP request moves to the Authentication step.
|
||||
This is shown as step **1** in the diagram.
|
||||
The cluster creation script or cluster admin configures the API server to run
|
||||
one or more Authenticator Modules.
|
||||
Authenticators are described in more detail [here](/docs/admin/authentication/).
|
||||
|
||||
The input to the authentication step is the entire HTTP request, however, it typically
|
||||
just examines the headers and/or client certificate.
|
||||
|
||||
Authentication modules include Client Certificates, Password, and Plain Tokens,
|
||||
Bootstrap Tokens, and JWT Tokens (used for service accounts).
|
||||
|
||||
Multiple authentication modules can be specified, in which case each one is tried in sequence,
|
||||
until one of them succeeds.
|
||||
|
||||
On GCE, Client Certificates, Password, Plain Tokens, and JWT Tokens are all enabled.
|
||||
|
||||
If the request cannot be authenticated, it is rejected with HTTP status code 401.
|
||||
Otherwise, the user is authenticated as a specific `username`, and the user name
|
||||
is available to subsequent steps to use in their decisions. Some authenticators
|
||||
also provide the group memberships of the user, while other authenticators
|
||||
do not.
|
||||
|
||||
While Kubernetes uses "usernames" for access control decisions and in request logging,
|
||||
it does not have a `user` object nor does it store usernames or other information about
|
||||
users in its object store.
|
||||
|
||||
## Authorization
|
||||
|
||||
After the request is authenticated as coming from a specific user, the request must be authorized. This is shown as step **2** in the diagram.
|
||||
|
||||
A request must include the username of the requester, the requested action, and the object affected by the action. The request is authorized if an existing policy declares that the user has permissions to complete the requested action.
|
||||
|
||||
For example, if Bob has the policy below, then he can read pods only in the namespace `projectCaribou`:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
|
||||
"kind": "Policy",
|
||||
"spec": {
|
||||
"user": "bob",
|
||||
"namespace": "projectCaribou",
|
||||
"resource": "pods",
|
||||
"readonly": true
|
||||
}
|
||||
}
|
||||
```
|
||||
If Bob makes the following request, the request is authorized because he is allowed to read objects in the `projectCaribou` namespace:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"resourceAttributes": {
|
||||
"namespace": "projectCaribou",
|
||||
"verb": "get",
|
||||
"group": "unicorn.example.org",
|
||||
"resource": "pods"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
If Bob makes a request to write (`create` or `update`) to the objects in the `projectCaribou` namespace, his authorization is denied. If Bob makes a request to read (`get`) objects in a different namespace such as `projectFish`, then his authorization is denied.
|
||||
|
||||
Kubernetes authorization requires that you use common REST attributes to interact with existing organization-wide or cloud-provider-wide access control systems. It is important to use REST formatting because these control systems might interact with other APIs besides the Kubernetes API.
|
||||
|
||||
Kubernetes supports multiple authorization modules, such as ABAC mode, RBAC Mode, and Webhook mode. When an administrator creates a cluster, they configured the authorization modules that should be used in the API server. If more than one authorization modules are configured, Kubernetes checks each module, and if any module authorizes the request, then the request can proceed. If all of the modules deny the request, then the request is denied (HTTP status code 403).
|
||||
|
||||
To learn more about Kubernetes authorization, including details about creating policies using the supported authorization modules, see [Authorization Overview](/docs/admin/authorization/).
|
||||
|
||||
|
||||
## Admission Control
|
||||
|
||||
Admission Control Modules are software modules that can modify or reject requests.
|
||||
In addition to the attributes available to Authorization Modules, Admission
|
||||
Control Modules can access the contents of the object that is being created or updated.
|
||||
They act on objects being created, deleted, updated or connected (proxy), but not reads.
|
||||
|
||||
Multiple admission controllers can be configured. Each is called in order.
|
||||
|
||||
This is shown as step **3** in the diagram.
|
||||
|
||||
Unlike Authentication and Authorization Modules, if any admission controller module
|
||||
rejects, then the request is immediately rejected.
|
||||
|
||||
In addition to rejecting objects, admission controllers can also set complex defaults for
|
||||
fields.
|
||||
|
||||
The available Admission Control Modules are described [here](/docs/admin/admission-controllers/).
|
||||
|
||||
Once a request passes all admission controllers, it is validated using the validation routines
|
||||
for the corresponding API object, and then written to the object store (shown as step **4**).
|
||||
|
||||
|
||||
## API Server Ports and IPs
|
||||
|
||||
The previous discussion applies to requests sent to the secure port of the API server
|
||||
(the typical case). The API server can actually serve on 2 ports:
|
||||
|
||||
By default the Kubernetes API server serves HTTP on 2 ports:
|
||||
|
||||
1. `Localhost Port`:
|
||||
|
||||
- is intended for testing and bootstrap, and for other components of the master node
|
||||
(scheduler, controller-manager) to talk to the API
|
||||
- no TLS
|
||||
- default is port 8080, change with `--insecure-port` flag.
|
||||
- default IP is localhost, change with `--insecure-bind-address` flag.
|
||||
- request **bypasses** authentication and authorization modules.
|
||||
- request handled by admission control module(s).
|
||||
- protected by need to have host access
|
||||
|
||||
2. `Secure Port`:
|
||||
|
||||
- use whenever possible
|
||||
- uses TLS. Set cert with `--tls-cert-file` and key with `--tls-private-key-file` flag.
|
||||
- default is port 6443, change with `--secure-port` flag.
|
||||
- default IP is first non-localhost network interface, change with `--bind-address` flag.
|
||||
- request handled by authentication and authorization modules.
|
||||
- request handled by admission control module(s).
|
||||
- authentication and authorization modules run.
|
||||
|
||||
When the cluster is created by `kube-up.sh`, on Google Compute Engine (GCE),
|
||||
and on several other cloud providers, the API server serves on port 443. On
|
||||
GCE, a firewall rule is configured on the project to allow external HTTPS
|
||||
access to the API. Other cluster setup methods vary.
|
||||
|
||||
@@ -0,0 +1,632 @@
|
||||
---
|
||||
reviewers:
|
||||
- lavalamp
|
||||
- davidopp
|
||||
- derekwaynecarr
|
||||
- erictune
|
||||
- janetkuo
|
||||
- thockin
|
||||
title: Using Admission Controllers
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## What are they?
|
||||
|
||||
An admission controller is a piece of code that intercepts requests to the
|
||||
Kubernetes API server prior to persistence of the object, but after the request
|
||||
is authenticated and authorized. The controllers consist of the
|
||||
[list](#what-does-each-admission-controller-do) below, are compiled into the
|
||||
`kube-apiserver` binary, and may only be configured by the cluster
|
||||
administrator. In that list, there are two special controllers:
|
||||
MutatingAdmissionWebhook and ValidatingAdmissionWebhook. These execute the
|
||||
mutating and validating (respectively) [admission control
|
||||
webhooks](/docs/admin/extensible-admission-controllers.md#external-admission-webhooks)
|
||||
which are configured in the API.
|
||||
|
||||
Admission controllers may be "validating", "mutating", or both. Mutating
|
||||
controllers may modify the objects they admit; validating controllers may not.
|
||||
|
||||
The admission control process proceeds in two phases. In the first phase,
|
||||
mutating admission controllers are run. In the second phase, validating
|
||||
admission controllers are run. Note again that some of the controllers are
|
||||
both.
|
||||
|
||||
If any of the controllers in either phase reject the request, the entire
|
||||
request is rejected immediately and an error is returned to the end-user.
|
||||
|
||||
Finally, in addition to sometimes mutating the object in question, admission
|
||||
controllers may sometimes have side effects, that is, mutate related
|
||||
resources as part of request processing. Incrementing quota usage is the
|
||||
canonical example of why this is necessary. Any such side-effect needs a
|
||||
corresponding reclamation or reconciliation process, as a given admission
|
||||
controller does not know for sure that a given request will pass all of the
|
||||
other admission controllers.
|
||||
|
||||
## Why do I need them?
|
||||
|
||||
Many advanced features in Kubernetes require an admission controller to be enabled in order
|
||||
to properly support the feature. As a result, a Kubernetes API server that is not properly
|
||||
configured with the right set of admission controllers is an incomplete server and will not
|
||||
support all the features you expect.
|
||||
|
||||
## How do I turn on an admission controller?
|
||||
|
||||
The Kubernetes API server flag `enable-admission-plugins` takes a comma-delimited list of admission control plugins to invoke prior to modifying objects in the cluster.
|
||||
For example, the following command line enables the `NamespaceLifecycle` and the `LimitRanger`
|
||||
admission control plugins:
|
||||
|
||||
```shell
|
||||
kube-apiserver --enable-admission-plugins=NamespaceLifecyle,LimitRanger ...
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
**Note**: Depending on the way your Kubernetes cluster is deployed and how the
|
||||
API server is started, you may need to apply the settings in different ways.
|
||||
For example, you may have to modify the systemd unit file if the API server is
|
||||
deployed as a systemd service, you may modify the manifest file for the API
|
||||
server if Kubernetes is deployed in a self-hosted way.
|
||||
{{< /note >}}
|
||||
|
||||
## How do I turn off an admission controller?
|
||||
|
||||
The Kubernetes API server flag `disable-admission-plugins` takes a comma-delimited list of admission control plugins to be disabled, even if they are in the list of plugins enabled by default.
|
||||
|
||||
```shell
|
||||
kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...
|
||||
```
|
||||
|
||||
## What does each admission controller do?
|
||||
|
||||
### AlwaysAdmit (DEPRECATED)
|
||||
|
||||
Use this admission controller by itself to pass-through all requests. AlwaysAdmit is DEPRECATED as no real meaning.
|
||||
|
||||
### AlwaysPullImages
|
||||
|
||||
This admission controller modifies every new Pod to force the image pull policy to Always. This is useful in a
|
||||
multitenant cluster so that users can be assured that their private images can only be used by those
|
||||
who have the credentials to pull them. Without this admission controller, once an image has been pulled to a
|
||||
node, any pod from any user can use it simply by knowing the image's name (assuming the Pod is
|
||||
scheduled onto the right node), without any authorization check against the image. When this admission controller
|
||||
is enabled, images are always pulled prior to starting containers, which means valid credentials are
|
||||
required.
|
||||
|
||||
### AlwaysDeny (DEPRECATED)
|
||||
|
||||
Rejects all requests. AlwaysDeny is DEPRECATED as no real meaning.
|
||||
|
||||
### DefaultStorageClass
|
||||
|
||||
This admission controller observes creation of `PersistentVolumeClaim` objects that do not request any specific storage class
|
||||
and automatically adds a default storage class to them.
|
||||
This way, users that do not request any special storage class do not need to care about them at all and they
|
||||
will get the default one.
|
||||
|
||||
This admission controller does not do anything when no default storage class is configured. When more than one storage
|
||||
class is marked as default, it rejects any creation of `PersistentVolumeClaim` with an error and an administrator
|
||||
must revisit their `StorageClass` objects and mark only one as default.
|
||||
This admission controller ignores any `PersistentVolumeClaim` updates; it acts only on creation.
|
||||
|
||||
See [persistent volume](/docs/concepts/storage/persistent-volumes/) documentation about persistent volume claims and
|
||||
storage classes and how to mark a storage class as default.
|
||||
|
||||
### DefaultTolerationSeconds
|
||||
|
||||
This admission controller sets the default forgiveness toleration for pods to tolerate
|
||||
the taints `notready:NoExecute` and `unreachable:NoExecute` for 5 minutes,
|
||||
if the pods don't already have toleration for taints
|
||||
`node.kubernetes.io/not-ready:NoExecute` or
|
||||
`node.alpha.kubernetes.io/unreachable:NoExecute`.
|
||||
|
||||
### DenyExecOnPrivileged (deprecated)
|
||||
|
||||
This admission controller 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
|
||||
commands in those containers, we strongly encourage enabling this admission controller.
|
||||
|
||||
This functionality has been merged into [DenyEscalatingExec](#denyescalatingexec).
|
||||
|
||||
### DenyEscalatingExec
|
||||
|
||||
This admission controller 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 admission controller.
|
||||
|
||||
### EventRateLimit (alpha)
|
||||
|
||||
This admission controller mitigates the problem where the API server gets flooded by
|
||||
event requests. The cluster admin can specify event rate limits by:
|
||||
|
||||
* Enabling the `EventRateLimit` admission controller;
|
||||
* Referencing an `EventRateLimit` configuration file from the file provided to the API
|
||||
server's command line flag `--admission-control-config-file`:
|
||||
|
||||
```yaml
|
||||
kind: AdmissionConfiguration
|
||||
apiVersion: apiserver.k8s.io/v1alpha1
|
||||
plugins:
|
||||
- name: EventRateLimit
|
||||
path: eventconfig.yaml
|
||||
...
|
||||
```
|
||||
|
||||
There are four types of limits that can be specified in the configuration:
|
||||
|
||||
* `Server`: All event requests received by the API server share a single bucket.
|
||||
* `Namespace`: Each namespace has a dedicated bucket.
|
||||
* `User`: Each user is allocated a bucket.
|
||||
* `SourceAndObject`: A bucket is assigned by each combination of source and
|
||||
involved object of the event.
|
||||
|
||||
Below is a sample `eventconfig.yaml` for such a configuration:
|
||||
|
||||
```yaml
|
||||
kind: Configuration
|
||||
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
|
||||
limits:
|
||||
- type: Namespace
|
||||
qps: 50
|
||||
burst: 100
|
||||
cacheSize: 2000
|
||||
- type: User
|
||||
qps: 10
|
||||
burst: 50
|
||||
```
|
||||
|
||||
See the [EventRateLimit proposal](https://git.k8s.io/community/contributors/design-proposals/api-machinery/admission_control_event_rate_limit.md)
|
||||
for more details.
|
||||
|
||||
### ExtendedResourceToleration
|
||||
|
||||
This plug-in facilitates creation of dedicated nodes with extended resources.
|
||||
If operators want to create dedicated nodes with extended resources (like GPUs, FPGAs etc.), they are expected to
|
||||
[taint the node](/docs/concepts/configuration/taint-and-toleration/#example-use-cases) with the extended resource
|
||||
name as the key. This admission controller, if enabled, automatically
|
||||
adds tolerations for such taints to pods requesting extended resources, so users don't have to manually
|
||||
add these tolerations.
|
||||
|
||||
### ImagePolicyWebhook
|
||||
|
||||
The ImagePolicyWebhook admission controller allows a backend webhook to make admission decisions.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
ImagePolicyWebhook uses a configuration file to set options for the behavior of the backend.
|
||||
This file may be json or yaml and has the following format:
|
||||
|
||||
```yaml
|
||||
imagePolicy:
|
||||
kubeConfigFile: /path/to/kubeconfig/for/backend
|
||||
# time in s to cache approval
|
||||
allowTTL: 50
|
||||
# time in s to cache denial
|
||||
denyTTL: 50
|
||||
# time in ms to wait between retries
|
||||
retryBackoff: 500
|
||||
# determines behavior if the webhook backend fails
|
||||
defaultAllow: true
|
||||
```
|
||||
|
||||
Reference the ImagePolicyWebhook configuration file from the file provided to the API server's command line flag `--admission-control-config-file`:
|
||||
|
||||
```yaml
|
||||
kind: AdmissionConfiguration
|
||||
apiVersion: apiserver.k8s.io/v1alpha1
|
||||
plugins:
|
||||
- name: ImagePolicyWebhook
|
||||
path: imagepolicyconfig.yaml
|
||||
...
|
||||
```
|
||||
|
||||
The ImagePolicyWebhook config file must reference a [kubeconfig](/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/) formatted file which sets up the connection to the backend. It is required that the backend communicate over TLS.
|
||||
|
||||
The kubeconfig file's cluster field must point to the remote service, and the user field must contain the returned authorizer.
|
||||
|
||||
```yaml
|
||||
# clusters refers to the remote service.
|
||||
clusters:
|
||||
- name: name-of-remote-imagepolicy-service
|
||||
cluster:
|
||||
certificate-authority: /path/to/ca.pem # CA for verifying the remote service.
|
||||
server: https://images.example.com/policy # URL of remote service to query. Must use 'https'.
|
||||
|
||||
# users refers to the API server's webhook configuration.
|
||||
users:
|
||||
- name: name-of-api-server
|
||||
user:
|
||||
client-certificate: /path/to/cert.pem # cert for the webhook admission controller to use
|
||||
client-key: /path/to/key.pem # key matching the cert
|
||||
```
|
||||
For additional HTTP configuration, refer to the [kubeconfig](/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/) documentation.
|
||||
|
||||
#### Request Payloads
|
||||
|
||||
When faced with an admission decision, the API Server POSTs a JSON serialized `imagepolicy.k8s.io/v1alpha1` `ImageReview` object describing the action. This object contains fields describing the containers being admitted, as well as any pod annotations that match `*.image-policy.k8s.io/*`.
|
||||
|
||||
Note that webhook API objects are subject to the same versioning compatibility rules as other Kubernetes API objects. Implementers should be aware of looser compatibility promises for alpha objects and check the "apiVersion" field of the request to ensure correct deserialization. Additionally, the API Server must enable the imagepolicy.k8s.io/v1alpha1 API extensions group (`--runtime-config=imagepolicy.k8s.io/v1alpha1=true`).
|
||||
|
||||
An example request body:
|
||||
|
||||
```
|
||||
{
|
||||
"apiVersion":"imagepolicy.k8s.io/v1alpha1",
|
||||
"kind":"ImageReview",
|
||||
"spec":{
|
||||
"containers":[
|
||||
{
|
||||
"image":"myrepo/myimage:v1"
|
||||
},
|
||||
{
|
||||
"image":"myrepo/myimage@sha256:beb6bd6a68f114c1dc2ea4b28db81bdf91de202a9014972bec5e4d9171d90ed"
|
||||
}
|
||||
],
|
||||
"annotations":[
|
||||
"mycluster.image-policy.k8s.io/ticket-1234": "break-glass"
|
||||
],
|
||||
"namespace":"mynamespace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The remote service is expected to fill the ImageReviewStatus field of the request and respond to either allow or disallow access. The response body's "spec" field is ignored and may be omitted. A permissive response would return:
|
||||
|
||||
```
|
||||
{
|
||||
"apiVersion": "imagepolicy.k8s.io/v1alpha1",
|
||||
"kind": "ImageReview",
|
||||
"status": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To disallow access, the service would return:
|
||||
|
||||
```
|
||||
{
|
||||
"apiVersion": "imagepolicy.k8s.io/v1alpha1",
|
||||
"kind": "ImageReview",
|
||||
"status": {
|
||||
"allowed": false,
|
||||
"reason": "image currently blacklisted"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For further documentation refer to the `imagepolicy.v1alpha1` API objects and `plugin/pkg/admission/imagepolicy/admission.go`.
|
||||
|
||||
#### Extending with Annotations
|
||||
|
||||
All annotations on a Pod that match `*.image-policy.k8s.io/*` are sent to the webhook. Sending annotations allows users who are aware of the image policy backend to send extra information to it, and for different backends implementations to accept different information.
|
||||
|
||||
Examples of information you might put here are:
|
||||
|
||||
* request to "break glass" to override a policy, in case of emergency.
|
||||
* a ticket number from a ticket system that documents the break-glass request
|
||||
* provide a hint to the policy server as to the imageID of the image being provided, to save it a lookup
|
||||
|
||||
In any case, the annotations are provided by the user and are not validated by Kubernetes in any way. In the future, if an annotation is determined to be widely useful, it may be promoted to a named field of ImageReviewSpec.
|
||||
|
||||
### Initializers (alpha)
|
||||
|
||||
The admission controller determines the initializers of a resource based on the existing
|
||||
`InitializerConfiguration`s. It sets the pending initializers by modifying the
|
||||
metadata of the resource to be created.
|
||||
For more information, please check [Dynamic Admission Control](/docs/admin/extensible-admission-controllers.md).
|
||||
|
||||
### InitialResources (experimental)
|
||||
|
||||
This admission controller observes pod creation requests. If a container omits compute resource requests and limits,
|
||||
then the admission controller auto-populates a compute resource request based on historical usage of containers running the same image.
|
||||
If there is not enough data to make a decision the Request is left unchanged.
|
||||
When the admission controller sets a compute resource request, it does this by *annotating*
|
||||
the pod spec rather than mutating the `container.resources` fields.
|
||||
The annotations added contain the information on what compute resources were auto-populated.
|
||||
|
||||
See the [InitialResources proposal](https://git.k8s.io/community/contributors/design-proposals/autoscaling/initial-resources.md) for more details.
|
||||
|
||||
### LimitPodHardAntiAffinityTopology
|
||||
|
||||
This admission controller denies any pod that defines `AntiAffinity` topology key other than
|
||||
`kubernetes.io/hostname` in `requiredDuringSchedulingRequiredDuringExecution`.
|
||||
|
||||
### LimitRanger
|
||||
|
||||
This admission controller will observe the incoming request and ensure that it does not violate any of the constraints
|
||||
enumerated in the `LimitRange` object in a `Namespace`. If you are using `LimitRange` objects in
|
||||
your Kubernetes deployment, you MUST use this admission controller to enforce those constraints. LimitRanger can also
|
||||
be used to apply default resource requests to Pods that don't specify any; currently, the default LimitRanger
|
||||
applies a 0.1 CPU requirement to all Pods in the `default` namespace.
|
||||
|
||||
See the [limitRange design doc](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_limit_range.md) and the [example of Limit Range](/docs/tasks/configure-pod-container/limit-range/) for more details.
|
||||
|
||||
### MutatingAdmissionWebhook (beta in 1.9)
|
||||
|
||||
This admission controller calls any mutating webhooks which match the request. Matching
|
||||
webhooks are called in serial; each one may modify the object if it desires.
|
||||
|
||||
This admission controller (as implied by the name) only runs in the mutating phase.
|
||||
|
||||
If a webhook called by this has side effects (for example, decrementing quota) it
|
||||
*must* have a reconciliation system, as it is not guaranteed that subsequent
|
||||
webhooks or validating admission controllers will permit the request to finish.
|
||||
|
||||
If you disable the MutatingAdmissionWebhook, you must also disable the
|
||||
`MutatingWebhookConfiguration` object in the `admissionregistration.k8s.io/v1beta1`
|
||||
group/version via the `--runtime-config` flag (both are on by default in
|
||||
versions >= 1.9).
|
||||
|
||||
#### Use caution when authoring and installing mutating webhooks
|
||||
|
||||
* Users may be confused when the objects they try to create are different from
|
||||
what they get back.
|
||||
* Built in control loops may break when the objects they try to create are
|
||||
different when read back.
|
||||
* Setting originally unset fields is less likely to cause problems than
|
||||
overwriting fields set in the original request. Avoid doing the latter.
|
||||
* This is a beta feature. Future versions of Kubernetes may restrict the types of
|
||||
mutations these webhooks can make.
|
||||
* Future changes to control loops for built-in resources or third-party resources
|
||||
may break webhooks that work well today. Even when the webhook installation API
|
||||
is finalized, not all possible webhook behaviors will be guaranteed to be supported
|
||||
indefinitely.
|
||||
|
||||
### NamespaceAutoProvision
|
||||
|
||||
This admission controller examines all incoming requests on namespaced resources and checks
|
||||
if the referenced namespace does exist.
|
||||
It creates a namespace if it cannot be found.
|
||||
This admission controller is useful in deployments that do not want to restrict creation of
|
||||
a namespace prior to its usage.
|
||||
|
||||
### NamespaceExists
|
||||
|
||||
This admission controller checks all requests on namespaced resources other than `Namespace` itself.
|
||||
If the namespace referenced from a request doesn't exist, the request is rejected.
|
||||
|
||||
### NamespaceLifecycle
|
||||
|
||||
This admission controller enforces that a `Namespace` that is undergoing termination cannot have new objects created in it,
|
||||
and ensures that requests in a non-existent `Namespace` are rejected. This admission controller also prevents deletion of
|
||||
three system reserved namespaces `default`, `kube-system`, `kube-public`.
|
||||
|
||||
A `Namespace` deletion kicks off a sequence of operations that remove all objects (pods, services, etc.) in that
|
||||
namespace. In order to enforce integrity of that process, we strongly recommend running this admission controller.
|
||||
|
||||
### NodeRestriction
|
||||
|
||||
This admission controller limits the `Node` and `Pod` objects a kubelet can modify. In order to be limited by this admission controller,
|
||||
kubelets must use credentials in the `system:nodes` group, with a username in the form `system:node:<nodeName>`.
|
||||
Such kubelets will only be allowed to modify their own `Node` API object, and only modify `Pod` API objects that are bound to their node.
|
||||
Future versions may add additional restrictions to ensure kubelets have the minimal set of permissions required to operate correctly.
|
||||
|
||||
### OwnerReferencesPermissionEnforcement
|
||||
|
||||
This admission controller protects the access to the `metadata.ownerReferences` of an object
|
||||
so that only users with "delete" permission to the object can change it.
|
||||
This admission controller also protects the access to `metadata.ownerReferences[x].blockOwnerDeletion`
|
||||
of an object, so that only users with "update" permission to the `finalizers`
|
||||
subresource of the referenced *owner* can change it.
|
||||
|
||||
### PersistentVolumeLabel (DEPRECATED)
|
||||
|
||||
This admission controller automatically attaches region or zone labels to PersistentVolumes
|
||||
as defined by the cloud provider (for example, GCE or AWS).
|
||||
It helps ensure the Pods and the PersistentVolumes mounted are in the same
|
||||
region and/or zone.
|
||||
If the admission controller doesn't support automatic labelling your PersistentVolumes, you
|
||||
may need to add the labels manually to prevent pods from mounting volumes from
|
||||
a different zone. PersistentVolumeLabel is DEPRECATED and labeling persistent volumes has been taken over by [cloud controller manager](/docs/tasks/administer-cluster/running-cloud-controller/).
|
||||
|
||||
### PodNodeSelector
|
||||
|
||||
This admission controller defaults and limits what node selectors may be used within a namespace by reading a namespace annotation and a global configuration.
|
||||
|
||||
#### Configuration File Format
|
||||
|
||||
`PodNodeSelector` uses a configuration file to set options for the behavior of the backend.
|
||||
Note that the configuration file format will move to a versioned file in a future release.
|
||||
This file may be json or yaml and has the following format:
|
||||
|
||||
```yaml
|
||||
podNodeSelectorPluginConfig:
|
||||
clusterDefaultNodeSelector: <node-selectors-labels>
|
||||
namespace1: <node-selectors-labels>
|
||||
namespace2: <node-selectors-labels>
|
||||
```
|
||||
|
||||
Reference the `PodNodeSelector` configuration file from the file provided to the API server's command line flag `--admission-control-config-file`:
|
||||
|
||||
```yaml
|
||||
kind: AdmissionConfiguration
|
||||
apiVersion: apiserver.k8s.io/v1alpha1
|
||||
plugins:
|
||||
- name: PodNodeSelector
|
||||
path: podnodeselector.yaml
|
||||
...
|
||||
```
|
||||
|
||||
#### Configuration Annotation Format
|
||||
`PodNodeSelector` uses the annotation key `scheduler.alpha.kubernetes.io/node-selector` to assign node selectors to namespaces.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/node-selector: <node-selectors-labels>
|
||||
name: namespace3
|
||||
```
|
||||
|
||||
#### Internal Behavior
|
||||
This admission controller has the following behavior:
|
||||
1. If the `Namespace` has an annotation with a key `scheduler.alpha.kubernetes.io/node-selector`, use its value as the
|
||||
node selector.
|
||||
1. If the namespace lacks such an annotation, use the `clusterDefaultNodeSelector` defined in the `PodNodeSelector`
|
||||
plugin configuration file as the node selector.
|
||||
1. Evaluate the pod's node selector against the namespace node selector for conflicts. Conflicts result in rejection.
|
||||
1. Evaluate the pod's node selector against the namespace-specific whitelist defined the plugin configuration file.
|
||||
Conflicts result in rejection.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** PodNodeSelector allows forcing pods to run on specifically labeled nodes. Also see the PodTolerationRestriction
|
||||
admission plugin, which allows preventing pods from running on specifically tainted nodes.
|
||||
{{< /note >}}
|
||||
|
||||
### PersistentVolumeClaimResize
|
||||
|
||||
This admission controller implements additional validations for checking incoming `PersistentVolumeClaim` resize requests.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Support for volume resizing is available as an alpha feature. Admins must set the feature gate `ExpandPersistentVolumes`
|
||||
to `true` to enable resizing.
|
||||
{{< /note >}}
|
||||
|
||||
After enabling the `ExpandPersistentVolumes` feature gate, enabling the `PersistentVolumeClaimResize` admission
|
||||
controller is recommended, too. This admission controller prevents resizing of all claims by default unless a claim's `StorageClass`
|
||||
explicitly enables resizing by setting `allowVolumeExpansion` to `true`.
|
||||
|
||||
For example: all `PersistentVolumeClaim`s created from the following `StorageClass` support volume expansion:
|
||||
|
||||
```yaml
|
||||
kind: StorageClass
|
||||
apiVersion: storage.k8s.io/v1
|
||||
metadata:
|
||||
name: gluster-vol-default
|
||||
provisioner: kubernetes.io/glusterfs
|
||||
parameters:
|
||||
resturl: "http://192.168.10.100:8080"
|
||||
restuser: ""
|
||||
secretNamespace: ""
|
||||
secretName: ""
|
||||
allowVolumeExpansion: true
|
||||
```
|
||||
|
||||
For more information about persistent volume claims, see ["PersistentVolumeClaims"](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims).
|
||||
|
||||
### PodPreset
|
||||
|
||||
This admission controller injects a pod with the fields specified in a matching PodPreset.
|
||||
See also [PodPreset concept](/docs/concepts/workloads/pods/podpreset/) and
|
||||
[Inject Information into Pods Using a PodPreset](/docs/tasks/inject-data-application/podpreset)
|
||||
for more information.
|
||||
|
||||
### PodSecurityPolicy
|
||||
|
||||
This admission controller acts on creation and modification of the pod and determines if it should be admitted
|
||||
based on the requested security context and the available Pod Security Policies.
|
||||
|
||||
For Kubernetes < 1.6.0, the API Server must enable the extensions/v1beta1/podsecuritypolicy API
|
||||
extensions group (`--runtime-config=extensions/v1beta1/podsecuritypolicy=true`).
|
||||
|
||||
See also [Pod Security Policy documentation](/docs/concepts/policy/pod-security-policy/)
|
||||
for more information.
|
||||
|
||||
### PodTolerationRestriction
|
||||
|
||||
This admission controller first verifies any conflict between a pod's tolerations and its
|
||||
namespace's tolerations, and rejects the pod request if there is a conflict.
|
||||
It then merges the namespace's tolerations into the pod's tolerations.
|
||||
The resulting tolerations are checked against the namespace's whitelist of
|
||||
tolerations. If the check succeeds, the pod request is admitted otherwise
|
||||
rejected.
|
||||
|
||||
If the pod's namespace does not have any associated default or whitelist of
|
||||
tolerations, then the cluster-level default or whitelist of tolerations are used
|
||||
instead if specified.
|
||||
|
||||
Tolerations to a namespace are assigned via the
|
||||
`scheduler.alpha.kubernetes.io/defaultTolerations` and
|
||||
`scheduler.alpha.kubernetes.io/tolerationsWhitelist`
|
||||
annotation keys.
|
||||
|
||||
### Priority
|
||||
|
||||
The priority admission controller uses the `priorityClassName` field and populates the integer value of the priority. If the priority class is not found, the Pod is rejected.
|
||||
|
||||
### ResourceQuota
|
||||
|
||||
This admission controller will observe the incoming request and ensure that it does not violate any of the constraints
|
||||
enumerated in the `ResourceQuota` object in a `Namespace`. If you are using `ResourceQuota`
|
||||
objects in your Kubernetes deployment, you MUST use this admission controller to enforce quota constraints.
|
||||
|
||||
See the [resourceQuota design doc](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md) and the [example of Resource Quota](/docs/concepts/policy/resource-quotas/) for more details.
|
||||
|
||||
|
||||
### SecurityContextDeny
|
||||
|
||||
This admission controller will deny any pod that attempts to set certain escalating [SecurityContext](/docs/user-guide/security-context) fields. This should be enabled if a cluster doesn't utilize [pod security policies](/docs/user-guide/pod-security-policy) to restrict the set of values a security context can take.
|
||||
|
||||
### ServiceAccount
|
||||
|
||||
This admission controller implements automation for [serviceAccounts](/docs/user-guide/service-accounts).
|
||||
We strongly recommend using this admission controller if you intend to make use of Kubernetes `ServiceAccount` objects.
|
||||
|
||||
### Storage Object in Use Protection (beta)
|
||||
{{< feature-state for_k8s_version="v1.10" state="beta" >}}
|
||||
The `StorageObjectInUseProtection` plugin adds the `kubernetes.io/pvc-protection` or `kubernetes.io/pv-protection` finalizers to newly created Persistent Volume Claims (PVCs) or Persistent Volumes (PV). In case a user deletes a PVC or PV the PVC or PV is not removed until the finalizer is removed from the PVC or PV by PVC or PV Protection Controller. Refer to the [Storage Object in Use Protection](/docs/concepts/storage/persistent-volumes/#storage-object-in-use-protection) for more detailed information.
|
||||
|
||||
### ValidatingAdmissionWebhook (alpha in 1.8; beta in 1.9)
|
||||
|
||||
This admission controller calls any validating webhooks which match the request. Matching
|
||||
webhooks are called in parallel; if any of them rejects the request, the request
|
||||
fails. This admission controller only runs in the validation phase; the webhooks it calls may not
|
||||
mutate the object, as opposed to the webhooks called by the `MutatingAdmissionWebhook` admission controller.
|
||||
|
||||
If a webhook called by this has side effects (for example, decrementing quota) it
|
||||
*must* have a reconciliation system, as it is not guaranteed that subsequent
|
||||
webhooks or other validating admission controllers will permit the request to finish.
|
||||
|
||||
If you disable the ValidatingAdmissionWebhook, you must also disable the
|
||||
`ValidatingWebhookConfiguration` object in the `admissionregistration.k8s.io/v1beta1`
|
||||
group/version via the `--runtime-config` flag (both are on by default in
|
||||
versions >= 1.9).
|
||||
|
||||
|
||||
## Is there a recommended set of admission controllers to use?
|
||||
|
||||
Yes.
|
||||
For Kubernetes >= 1.9.0, we strongly recommend running the following set of admission controllers (order matters for 1.9 but not >1.10):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
|
||||
```
|
||||
|
||||
It's worth reiterating that in 1.9 and up, these happen in a mutating phase
|
||||
and a validating phase, and that e.g. `ResourceQuota` runs in the validating
|
||||
phase, and therefore is the last admission controller to run.
|
||||
`MutatingAdmissionWebhook` appears before it in this list, because it runs
|
||||
in the mutating phase.
|
||||
|
||||
For earlier versions, there was no concept of validating vs mutating and the
|
||||
admission controllers ran in the exact order specified.
|
||||
|
||||
For Kubernetes >= 1.6.0, we strongly recommend running the following set of admission controllers (order matters):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
|
||||
```
|
||||
|
||||
For Kubernetes >= 1.4.0, we strongly recommend running the following set of admission controllers (order matters):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
|
||||
```
|
||||
|
||||
For Kubernetes >= 1.2.0, we strongly recommend running the following set of admission controllers (order matters):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota
|
||||
```
|
||||
|
||||
For Kubernetes >= 1.0.0, we strongly recommend running the following set of admission controllers (order matters):
|
||||
|
||||
```shell
|
||||
--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,PersistentVolumeLabel,ResourceQuota
|
||||
```
|
||||
@@ -0,0 +1,842 @@
|
||||
---
|
||||
reviewers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- ericchiang
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Authenticating
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Users in Kubernetes
|
||||
|
||||
All Kubernetes clusters have two categories of users: service accounts managed
|
||||
by Kubernetes, and normal users.
|
||||
|
||||
Normal users are assumed to be managed by an outside, independent service. An
|
||||
admin distributing private keys, a user store like Keystone or Google Accounts,
|
||||
even a file with a list of usernames and passwords. In this regard, _Kubernetes
|
||||
does not have objects which represent normal user accounts._ Regular users
|
||||
cannot be added to a cluster through an API call.
|
||||
|
||||
In contrast, service accounts are users managed by the Kubernetes API. They are
|
||||
bound to specific namespaces, and created automatically by the API server or
|
||||
manually through API calls. Service accounts are tied to a set of credentials
|
||||
stored as `Secrets`, which are mounted into pods allowing in-cluster processes
|
||||
to talk to the Kubernetes API.
|
||||
|
||||
API requests are tied to either a normal user or a service account, or are treated
|
||||
as anonymous requests. This means every process inside or outside the cluster, from
|
||||
a human user typing `kubectl` on a workstation, to `kubelets` on nodes, to members
|
||||
of the control plane, must authenticate when making requests to the API server,
|
||||
or be treated as an anonymous user.
|
||||
|
||||
## Authentication strategies
|
||||
|
||||
Kubernetes uses client certificates, bearer tokens, an authenticating proxy, or HTTP basic auth to
|
||||
authenticate API requests through authentication plugins. As HTTP requests are
|
||||
made to the API server, plugins attempt to associate the following attributes
|
||||
with the request:
|
||||
|
||||
* Username: a string which identifies the end user. Common values might be `kube-admin` or `jane@example.com`.
|
||||
* UID: a string which identifies the end user and attempts to be more consistent and unique than username.
|
||||
* Groups: a set of strings which associate users with a set of commonly grouped users.
|
||||
* Extra fields: a map of strings to list of strings which holds additional information authorizers may find useful.
|
||||
|
||||
All values are opaque to the authentication system and only hold significance
|
||||
when interpreted by an [authorizer](/docs/admin/authorization/).
|
||||
|
||||
You can enable multiple authentication methods at once. You should usually use at least two methods:
|
||||
|
||||
- service account tokens for service accounts
|
||||
- at least one other method for user authentication.
|
||||
|
||||
When multiple authenticator modules are enabled, the first module
|
||||
to successfully authenticate the request short-circuits evaluation.
|
||||
The API server does not guarantee the order authenticators run in.
|
||||
|
||||
The `system:authenticated` group is included in the list of groups for all authenticated users.
|
||||
|
||||
Integrations with other authentication protocols (LDAP, SAML, Kerberos, alternate x509 schemes, etc)
|
||||
can be accomplished using an [authenticating proxy](#authenticating-proxy) or the
|
||||
[authentication webhook](#webhook-token-authentication).
|
||||
|
||||
### X509 Client Certs
|
||||
|
||||
Client certificate authentication is enabled by passing the `--client-ca-file=SOMEFILE`
|
||||
option to API server. The referenced file must contain one or more certificates authorities
|
||||
to use to validate client certificates presented to the API server. If a client certificate
|
||||
is presented and verified, the common name of the subject is used as the user name for the
|
||||
request. As of Kubernetes 1.4, client certificates can also indicate a user's group memberships
|
||||
using the certificate's organization fields. To include multiple group memberships for a user,
|
||||
include multiple organization fields in the certificate.
|
||||
|
||||
For example, using the `openssl` command line tool to generate a certificate signing request:
|
||||
|
||||
``` bash
|
||||
openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"
|
||||
```
|
||||
|
||||
This would create a CSR for the username "jbeda", belonging to two groups, "app1" and "app2".
|
||||
|
||||
See [Managing Certificates](/docs/concepts/cluster-administration/certificates/) for how to generate a client cert.
|
||||
|
||||
### Static Token File
|
||||
|
||||
The API server reads bearer tokens from a file when given the `--token-auth-file=SOMEFILE` option on the command line. Currently, tokens last indefinitely, and the token list cannot be
|
||||
changed without restarting API server.
|
||||
|
||||
The token file is a csv file with a minimum of 3 columns: token, user name, user uid,
|
||||
followed by optional group names. Note, if you have more than one group the column must be
|
||||
double quoted e.g.
|
||||
|
||||
```conf
|
||||
token,user,uid,"group1,group2,group3"
|
||||
```
|
||||
|
||||
#### Putting a Bearer Token in a Request
|
||||
|
||||
When using bearer token authentication from an http client, the API
|
||||
server expects an `Authorization` header with a value of `Bearer
|
||||
THETOKEN`. The bearer token must be a character sequence that can be
|
||||
put in an HTTP header value using no more than the encoding and
|
||||
quoting facilities of HTTP. For example: if the bearer token is
|
||||
`31ada4fd-adec-460c-809a-9e56ceb75269` then it would appear in an HTTP
|
||||
header as shown below.
|
||||
|
||||
```http
|
||||
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
|
||||
```
|
||||
|
||||
### Bootstrap Tokens
|
||||
|
||||
This feature is currently in **alpha**.
|
||||
|
||||
To allow for streamlined bootstrapping for new clusters, Kubernetes includes a
|
||||
dynamically-managed Bearer token type called a *Bootstrap Token*. These tokens
|
||||
are stored as Secrets in the `kube-system` namespace, where they can be
|
||||
dynamically managed and created. Controller Manager contains a TokenCleaner
|
||||
controller that deletes bootstrap tokens as they expire.
|
||||
|
||||
The tokens are of the form `[a-z0-9]{6}.[a-z0-9]{16}`. The first component is a
|
||||
Token ID and the second component is the Token Secret. You specify the token
|
||||
in an HTTP header as follows:
|
||||
|
||||
```http
|
||||
Authorization: Bearer 781292.db7bc3a58fc5f07e
|
||||
```
|
||||
|
||||
You must enable the Bootstrap Token Authenticator with the
|
||||
`--experimental-bootstrap-token-auth` flag on the API Server. You must enable
|
||||
the TokenCleaner controller via the `--controllers` flag on the Controller
|
||||
Manager. This is done with something like `--controllers=*,tokencleaner`.
|
||||
`kubeadm` will do this for you if you are using it to bootstrapping a cluster.
|
||||
|
||||
The authenticator authenticates as `system:bootstrap:<Token ID>`. It is
|
||||
included in the `system:bootstrappers` group. The naming and groups are
|
||||
intentionally limited to discourage users from using these tokens past
|
||||
bootstrapping. The user names and group can be used (and are used by `kubeadm`)
|
||||
to craft the appropriate authorization policies to support bootstrapping a
|
||||
cluster.
|
||||
|
||||
Please see [Bootstrap Tokens](/docs/admin/bootstrap-tokens/) for in depth
|
||||
documentation on the Bootstrap Token authenticator and controllers along with
|
||||
how to manage these tokens with `kubeadm`.
|
||||
|
||||
### Static Password File
|
||||
|
||||
Basic authentication is enabled by passing the `--basic-auth-file=SOMEFILE`
|
||||
option to API server. Currently, the basic auth credentials last indefinitely,
|
||||
and the password cannot be changed without restarting API server. Note that basic
|
||||
authentication is currently supported for convenience while we finish making the
|
||||
more secure modes described above easier to use.
|
||||
|
||||
The basic auth file is a csv file with a minimum of 3 columns: password, user name, user id.
|
||||
In Kubernetes version 1.6 and later, you can specify an optional fourth column containing
|
||||
comma-separated group names. If you have more than one group, you must enclose the fourth
|
||||
column value in double quotes ("). See the following example:
|
||||
|
||||
```conf
|
||||
password,user,uid,"group1,group2,group3"
|
||||
```
|
||||
|
||||
When using basic authentication from an http client, the API server expects an `Authorization` header
|
||||
with a value of `Basic BASE64ENCODED(USER:PASSWORD)`.
|
||||
|
||||
### Service Account Tokens
|
||||
|
||||
A service account is an automatically enabled authenticator that uses signed
|
||||
bearer tokens to verify requests. The plugin takes two optional flags:
|
||||
|
||||
* `--service-account-key-file` A file containing a PEM encoded key for signing bearer tokens.
|
||||
If unspecified, the API server's TLS private key will be used.
|
||||
* `--service-account-lookup` If enabled, tokens which are deleted from the API will be revoked.
|
||||
|
||||
Service accounts are usually created automatically by the API server and
|
||||
associated with pods running in the cluster through the `ServiceAccount`
|
||||
[Admission Controller](/docs/admin/admission-controllers/). Bearer tokens are
|
||||
mounted into pods at well-known locations, and allow in-cluster processes to
|
||||
talk to the API server. Accounts may be explicitly associated with pods using the
|
||||
`serviceAccountName` field of a `PodSpec`.
|
||||
|
||||
NOTE: `serviceAccountName` is usually omitted because this is done automatically.
|
||||
|
||||
```
|
||||
apiVersion: apps/v1 # this apiVersion is relevant as of Kubernetes 1.9
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
# ...
|
||||
spec:
|
||||
serviceAccountName: bob-the-bot
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
```
|
||||
|
||||
Service account bearer tokens are perfectly valid to use outside the cluster and
|
||||
can be used to create identities for long standing jobs that wish to talk to the
|
||||
Kubernetes API. To manually create a service account, simply use the `kubectl
|
||||
create serviceaccount (NAME)` command. This creates a service account in the
|
||||
current namespace and an associated secret.
|
||||
|
||||
```
|
||||
$ kubectl create serviceaccount jenkins
|
||||
serviceaccount "jenkins" created
|
||||
$ kubectl get serviceaccounts jenkins -o yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
# ...
|
||||
secrets:
|
||||
- name: jenkins-token-1yvwg
|
||||
```
|
||||
|
||||
The created secret holds the public CA of the API server and a signed JSON Web
|
||||
Token (JWT).
|
||||
|
||||
```
|
||||
$ kubectl get secret jenkins-token-1yvwg -o yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
ca.crt: (APISERVER'S CA BASE64 ENCODED)
|
||||
namespace: ZGVmYXVsdA==
|
||||
token: (BEARER TOKEN BASE64 ENCODED)
|
||||
kind: Secret
|
||||
metadata:
|
||||
# ...
|
||||
type: kubernetes.io/service-account-token
|
||||
```
|
||||
|
||||
Note: values are base64 encoded because secrets are always base64 encoded.
|
||||
|
||||
The signed JWT can be used as a bearer token to authenticate as the given service
|
||||
account. See [above](#putting-a-bearer-token-in-a-request) for how the token is included
|
||||
in a request. Normally these secrets are mounted into pods for in-cluster access to
|
||||
the API server, but can be used from outside the cluster as well.
|
||||
|
||||
Service accounts authenticate with the username `system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)`,
|
||||
and are assigned to the groups `system:serviceaccounts` and `system:serviceaccounts:(NAMESPACE)`.
|
||||
|
||||
WARNING: Because service account tokens are stored in secrets, any user with
|
||||
read access to those secrets can authenticate as the service account. Be cautious
|
||||
when granting permissions to service accounts and read capabilities for secrets.
|
||||
|
||||
### OpenID Connect Tokens
|
||||
|
||||
[OpenID Connect](https://openid.net/connect/) is a flavor of OAuth2 supported by
|
||||
some OAuth2 providers, notably Azure Active Directory, Salesforce, and Google.
|
||||
The protocol's main extension of OAuth2 is an additional field returned with
|
||||
the access token called an [ID Token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken).
|
||||
This token is a JSON Web Token (JWT) with well known fields, such as a user's
|
||||
email, signed by the server.
|
||||
|
||||
To identify the user, the authenticator uses the `id_token` (not the `access_token`)
|
||||
from the OAuth2 [token response](https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse)
|
||||
as a bearer token. See [above](#putting-a-bearer-token-in-a-request) for how the token
|
||||
is included in a request.
|
||||
|
||||

|
||||
|
||||
1. Login to your identity provider
|
||||
2. Your identity provider will provide you with an `access_token`, `id_token` and a `refresh_token`
|
||||
3. When using `kubectl`, use your `id_token` with the `--token` flag or add it directly to your `kubeconfig`
|
||||
4. `kubectl` sends your `id_token` in a header called Authorization to the API server
|
||||
5. The API server will make sure the JWT signature is valid by checking against the certificate named in the configuration
|
||||
6. Check to make sure the `id_token` hasn't expired
|
||||
7. Make sure the user is authorized
|
||||
8. Once authorized the API server returns a response to `kubectl`
|
||||
9. `kubectl` provides feedback to the user
|
||||
|
||||
Since all of the data needed to validate who you are is in the `id_token`, Kubernetes doesn't need to
|
||||
"phone home" to the identity provider. In a model where every request is stateless this provides a very scalable
|
||||
solution for authentication. It does offer a few challenges:
|
||||
|
||||
1. Kubernetes has no "web interface" to trigger the authentication process. There is no browser or interface to collect credentials which is why you need to authenticate to your identity provider first.
|
||||
2. The `id_token` can't be revoked, it's like a certificate so it should be short-lived (only a few minutes) so it can be very annoying to have to get a new token every few minutes.
|
||||
3. There's no easy way to authenticate to the Kubernetes dashboard without using the `kubectl proxy` command or a reverse proxy that injects the `id_token`.
|
||||
|
||||
|
||||
#### Configuring the API Server
|
||||
|
||||
To enable the plugin, configure the following flags on the API server:
|
||||
|
||||
| Parameter | Description | Example | Required |
|
||||
| --------- | ----------- | ------- | ------- |
|
||||
| `--oidc-issuer-url` | URL of the provider which allows the API server to discover public signing keys. Only URLs which use the `https://` scheme are accepted. This is typically the provider's discovery URL without a path, for example "https://accounts.google.com" or "https://login.salesforce.com". This URL should point to the level below .well-known/openid-configuration | If the discovery URL is `https://accounts.google.com/.well-known/openid-configuration`, the value should be `https://accounts.google.com` | Yes |
|
||||
| `--oidc-client-id` | A client id that all tokens must be issued for. | kubernetes | Yes |
|
||||
| `--oidc-username-claim` | JWT claim to use as the user name. By default `sub`, which is expected to be a unique identifier of the end user. Admins can choose other claims, such as `email` or `name`, depending on their provider. However, claims other than `email` will be prefixed with the issuer URL to prevent naming clashes with other plugins. | sub | No |
|
||||
| `--oidc-username-prefix` | Prefix prepended to username claims to prevent clashes with existing names (such as `system:` users). For example, the value `oidc:` will create usernames like `oidc:jane.doe`. If this flag isn't provided and `--oidc-user-claim` is a value other than `email` the prefix defaults to `( Issuer URL )#` where `( Issuer URL )` is the value of `--oidc-issuer-url`. The value `-` can be used to disable all prefixing. | `oidc:` | No |
|
||||
| `--oidc-groups-claim` | JWT claim to use as the user's group. If the claim is present it must be an array of strings. | groups | No |
|
||||
| `--oidc-groups-prefix` | Prefix prepended to group claims to prevent clashes with existing names (such as `system:` groups). For example, the value `oidc:` will create group names like `oidc:engineering` and `oidc:infra`. | `oidc:` | No |
|
||||
| `--oidc-ca-file` | The path to the certificate for the CA that signed your identity provider's web certificate. Defaults to the host's root CAs. | `/etc/kubernetes/ssl/kc-ca.pem` | No |
|
||||
|
||||
Importantly, the API server is not an OAuth2 client, rather it can only be
|
||||
configured to trust a single issuer. This allows the use of public providers,
|
||||
such as Google, without trusting credentials issued to third parties. Admins who
|
||||
wish to utilize multiple OAuth clients should explore providers which support the
|
||||
`azp` (authorized party) claim, a mechanism for allowing one client to issue
|
||||
tokens on behalf of another.
|
||||
|
||||
Kubernetes does not provide an OpenID Connect Identity Provider.
|
||||
You can use an existing public OpenID Connect Identity Provider (such as Google, or [others](http://connect2id.com/products/nimbus-oauth-openid-connect-sdk/openid-connect-providers)).
|
||||
Or, you can run your own Identity Provider, such as CoreOS [dex](https://github.com/coreos/dex), [Keycloak](https://github.com/keycloak/keycloak), CloudFoundry [UAA](https://github.com/cloudfoundry/uaa), or Tremolo Security's [OpenUnison](https://github.com/tremolosecurity/openunison).
|
||||
|
||||
For an identity provider to work with Kubernetes it must:
|
||||
|
||||
1. Support [OpenID connect discovery](https://openid.net/specs/openid-connect-discovery-1_0.html); not all do.
|
||||
2. Run in TLS with non-obsolete ciphers
|
||||
3. Have a CA signed certificate (even if the CA is not a commercial CA or is self signed)
|
||||
|
||||
A note about requirement #3 above, requiring a CA signed certificate. If you deploy your own identity provider (as opposed to one of the cloud providers like Google or Microsoft) you MUST have your identity provider's web server certificate signed by a certificate with the `CA` flag set to `TRUE`, even if it is self signed. This is due to GoLang's TLS client implementation being very strict to the standards around certificate validation. If you don't have a CA handy, you can use [this script](https://github.com/coreos/dex/blob/1ee5920c54f5926d6468d2607c728b71cfe98092/examples/k8s/gencert.sh) from the CoreOS team to create a simple CA and a signed certificate and key pair.
|
||||
Or you can use [this similar script](https://raw.githubusercontent.com/TremoloSecurity/openunison-qs-kubernetes/master/src/main/bash/makessl.sh) that generates SHA256 certs with a longer life and larger key size.
|
||||
|
||||
Setup instructions for specific systems:
|
||||
|
||||
- [UAA](http://apigee.com/about/blog/engineering/kubernetes-authentication-enterprise)
|
||||
- [Dex](https://speakerdeck.com/ericchiang/kubernetes-access-control-with-dex)
|
||||
- [OpenUnison](https://github.com/TremoloSecurity/openunison-qs-kubernetes)
|
||||
|
||||
#### Using kubectl
|
||||
|
||||
##### Option 1 - OIDC Authenticator
|
||||
|
||||
The first option is to use the kubectl `oidc` authenticator, which sets the `id_token` as a bearer token for all requests and refreshes the token once it expires. After you've logged into your provider, use kubectl to add your `id_token`, `refresh_token`, `client_id`, and `client_secret` to configure the plugin.
|
||||
|
||||
Providers that don't return an `id_token` as part of their refresh token response (e.g. [Okta](https://developer.okta.com/docs/api/resources/oidc.html#response-parameters-4)) aren't supported by this plugin and should use "Option 2" below.
|
||||
|
||||
```bash
|
||||
kubectl config set-credentials USER_NAME \
|
||||
--auth-provider=oidc \
|
||||
--auth-provider-arg=idp-issuer-url=( issuer url ) \
|
||||
--auth-provider-arg=client-id=( your client id ) \
|
||||
--auth-provider-arg=client-secret=( your client secret ) \
|
||||
--auth-provider-arg=refresh-token=( your refresh token ) \
|
||||
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
|
||||
--auth-provider-arg=id-token=( your id_token )
|
||||
```
|
||||
|
||||
As an example, running the below command after authenticating to your identity provider:
|
||||
|
||||
```bash
|
||||
kubectl config set-credentials mmosley \
|
||||
--auth-provider=oidc \
|
||||
--auth-provider-arg=idp-issuer-url=https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP \
|
||||
--auth-provider-arg=client-id=kubernetes \
|
||||
--auth-provider-arg=client-secret=1db158f6-177d-4d9c-8a8b-d36869918ec5 \
|
||||
--auth-provider-arg=refresh-token=q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqHega4GAXlF+ma+vmYpFcHe5eZR+slBFpZKtQA= \
|
||||
--auth-provider-arg=idp-certificate-authority=/root/ca.pem \
|
||||
--auth-provider-arg=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
|
||||
```
|
||||
|
||||
Which would produce the below configuration:
|
||||
|
||||
```yaml
|
||||
users:
|
||||
- name: mmosley
|
||||
user:
|
||||
auth-provider:
|
||||
config:
|
||||
client-id: kubernetes
|
||||
client-secret: 1db158f6-177d-4d9c-8a8b-d36869918ec5
|
||||
id-token: eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
|
||||
idp-certificate-authority: /root/ca.pem
|
||||
idp-issuer-url: https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP
|
||||
refresh-token: q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXq
|
||||
name: oidc
|
||||
```
|
||||
Once your `id_token` expires, `kubectl` will attempt to refresh your `id_token` using your `refresh_token` and `client_secret` storing the new values for the `refresh_token` and `id_token` in your `.kube/config`.
|
||||
|
||||
|
||||
##### Option 2 - Use the `--token` Option
|
||||
|
||||
The `kubectl` command lets you pass in a token using the `--token` option. Simply copy and paste the `id_token` into this option:
|
||||
|
||||
```
|
||||
kubectl --token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL21sYi50cmVtb2xvLmxhbjo4MDQzL2F1dGgvaWRwL29pZGMiLCJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNDc0NTk2NjY5LCJqdGkiOiI2RDUzNXoxUEpFNjJOR3QxaWVyYm9RIiwiaWF0IjoxNDc0NTk2MzY5LCJuYmYiOjE0NzQ1OTYyNDksInN1YiI6Im13aW5kdSIsInVzZXJfcm9sZSI6WyJ1c2VycyIsIm5ldy1uYW1lc3BhY2Utdmlld2VyIl0sImVtYWlsIjoibXdpbmR1QG5vbW9yZWplZGkuY29tIn0.f2As579n9VNoaKzoF-dOQGmXkFKf1FMyNV0-va_B63jn-_n9LGSCca_6IVMP8pO-Zb4KvRqGyTP0r3HkHxYy5c81AnIh8ijarruczl-TK_yF5akjSTHFZD-0gRzlevBDiH8Q79NAr-ky0P4iIXS8lY9Vnjch5MF74Zx0c3alKJHJUnnpjIACByfF2SCaYzbWFMUNat-K1PaUk5-ujMBG7yYnr95xD-63n8CO8teGUAAEMx6zRjzfhnhbzX-ajwZLGwGUBT4WqjMs70-6a7_8gZmLZb2az1cZynkFRj2BaCkVT3A2RrjeEwZEtGXlMqKJ1_I2ulrOVsYx01_yD35-rw get nodes
|
||||
```
|
||||
|
||||
|
||||
### Webhook Token Authentication
|
||||
|
||||
Webhook authentication is a hook for verifying bearer tokens.
|
||||
|
||||
* `--authentication-token-webhook-config-file` a kubeconfig file describing how to access the remote webhook service.
|
||||
* `--authentication-token-webhook-cache-ttl` how long to cache authentication decisions. Defaults to two minutes.
|
||||
|
||||
The configuration file uses the [kubeconfig](/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/)
|
||||
file format. Within the file "users" refers to the API server webhook and
|
||||
"clusters" refers to the remote service. An example would be:
|
||||
|
||||
```yaml
|
||||
# clusters refers to the remote service.
|
||||
clusters:
|
||||
- name: name-of-remote-authn-service
|
||||
cluster:
|
||||
certificate-authority: /path/to/ca.pem # CA for verifying the remote service.
|
||||
server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'.
|
||||
|
||||
# users refers to the API server's webhook configuration.
|
||||
users:
|
||||
- name: name-of-api-server
|
||||
user:
|
||||
client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
|
||||
client-key: /path/to/key.pem # key matching the cert
|
||||
|
||||
# kubeconfig files require a context. Provide one for the API server.
|
||||
current-context: webhook
|
||||
contexts:
|
||||
- context:
|
||||
cluster: name-of-remote-authn-service
|
||||
user: name-of-api-sever
|
||||
name: webhook
|
||||
```
|
||||
|
||||
When a client attempts to authenticate with the API server using a bearer token
|
||||
as discussed [above](#putting-a-bearer-token-in-a-request),
|
||||
the authentication webhook POSTs a JSON-serialized `authentication.k8s.io/v1beta1` `TokenReview` object containing the token
|
||||
to the remote service. Kubernetes will not challenge a request that lacks such a header.
|
||||
|
||||
Note that webhook API objects are subject to the same [versioning compatibility rules](/docs/concepts/overview/kubernetes-api/)
|
||||
as other Kubernetes API objects. Implementers should be aware of looser
|
||||
compatibility promises for beta objects and check the "apiVersion" field of the
|
||||
request to ensure correct deserialization. Additionally, the API server must
|
||||
enable the `authentication.k8s.io/v1beta1` API extensions group (`--runtime-config=authentication.k8s.io/v1beta1=true`).
|
||||
|
||||
The POST body will be of the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authentication.k8s.io/v1beta1",
|
||||
"kind": "TokenReview",
|
||||
"spec": {
|
||||
"token": "(BEARERTOKEN)"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The remote service is expected to fill the `status` field of
|
||||
the request to indicate the success of the login. The response body's `spec`
|
||||
field is ignored and may be omitted. A successful validation of the bearer
|
||||
token would return:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authentication.k8s.io/v1beta1",
|
||||
"kind": "TokenReview",
|
||||
"status": {
|
||||
"authenticated": true,
|
||||
"user": {
|
||||
"username": "janedoe@example.com",
|
||||
"uid": "42",
|
||||
"groups": [
|
||||
"developers",
|
||||
"qa"
|
||||
],
|
||||
"extra": {
|
||||
"extrafield1": [
|
||||
"extravalue1",
|
||||
"extravalue2"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
An unsuccessful request would return:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authentication.k8s.io/v1beta1",
|
||||
"kind": "TokenReview",
|
||||
"status": {
|
||||
"authenticated": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
HTTP status codes can be used to supply additional error context.
|
||||
|
||||
|
||||
### Authenticating Proxy
|
||||
|
||||
The API server can be configured to identify users from request header values, such as `X-Remote-User`.
|
||||
It is designed for use in combination with an authenticating proxy, which sets the request header value.
|
||||
|
||||
* `--requestheader-username-headers` Required, case-insensitive. Header names to check, in order, for the user identity. The first header containing a value is used as the username.
|
||||
* `--requestheader-group-headers` 1.6+. Optional, case-insensitive. "X-Remote-Group" is suggested. Header names to check, in order, for the user's groups. All values in all specified headers are used as group names.
|
||||
* `--requestheader-extra-headers-prefix` 1.6+. Optional, case-insensitive. "X-Remote-Extra-" is suggested. Header prefixes to look for to determine extra information about the user (typically used by the configured authorization plugin). Any headers beginning with any of the specified prefixes have the prefix removed, the remainder of the header name becomes the extra key, and the header value is the extra value.
|
||||
|
||||
For example, with this configuration:
|
||||
|
||||
```
|
||||
--requestheader-username-headers=X-Remote-User
|
||||
--requestheader-group-headers=X-Remote-Group
|
||||
--requestheader-extra-headers-prefix=X-Remote-Extra-
|
||||
```
|
||||
|
||||
this request:
|
||||
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
X-Remote-User: fido
|
||||
X-Remote-Group: dogs
|
||||
X-Remote-Group: dachshunds
|
||||
X-Remote-Extra-Scopes: openid
|
||||
X-Remote-Extra-Scopes: profile
|
||||
```
|
||||
|
||||
would result in this user info:
|
||||
|
||||
```yaml
|
||||
name: fido
|
||||
groups:
|
||||
- dogs
|
||||
- dachshunds
|
||||
extra:
|
||||
scopes:
|
||||
- openid
|
||||
- profile
|
||||
```
|
||||
|
||||
|
||||
In order to prevent header spoofing, the authenticating proxy is required to present a valid client
|
||||
certificate to the API server for validation against the specified CA before the request headers are
|
||||
checked.
|
||||
|
||||
* `--requestheader-client-ca-file` Required. PEM-encoded certificate bundle. A valid client certificate must be presented and validated against the certificate authorities in the specified file before the request headers are checked for user names.
|
||||
* `--requestheader-allowed-names` Optional. List of common names (cn). If set, a valid client certificate with a Common Name (cn) in the specified list must be presented before the request headers are checked for user names. If empty, any Common Name is allowed.
|
||||
|
||||
|
||||
### Keystone Password
|
||||
|
||||
Keystone authentication is enabled by passing the `--experimental-keystone-url=<AuthURL>`
|
||||
option to the API server during startup. The plugin is implemented in
|
||||
`plugin/pkg/auth/authenticator/password/keystone/keystone.go` and currently uses
|
||||
basic auth to verify user by username and password.
|
||||
|
||||
If you have configured self-signed certificates for the Keystone server,
|
||||
you may need to set the `--experimental-keystone-ca-file=SOMEFILE` option when
|
||||
starting the Kubernetes API server. If you set the option, the Keystone
|
||||
server's certificate is verified by one of the authorities in the
|
||||
`experimental-keystone-ca-file`. Otherwise, the certificate is verified by
|
||||
the host's root Certificate Authority.
|
||||
|
||||
For details on how to use keystone to manage projects and users, refer to the
|
||||
[Keystone documentation](http://docs.openstack.org/developer/keystone/). Please
|
||||
note that this plugin is still experimental, under active development, and likely
|
||||
to change in subsequent releases.
|
||||
|
||||
Please refer to the [discussion](https://github.com/kubernetes/kubernetes/pull/11798#issuecomment-129655212),
|
||||
[blueprint](https://github.com/kubernetes/kubernetes/issues/11626) and [proposed
|
||||
changes](https://github.com/kubernetes/kubernetes/pull/25536) for more details.
|
||||
|
||||
## Anonymous requests
|
||||
|
||||
When enabled, requests that are not rejected by other configured authentication methods are
|
||||
treated as anonymous requests, and given a username of `system:anonymous` and a group of
|
||||
`system:unauthenticated`.
|
||||
|
||||
For example, on a server with token authentication configured, and anonymous access enabled,
|
||||
a request providing an invalid bearer token would receive a `401 Unauthorized` error.
|
||||
A request providing no bearer token would be treated as an anonymous request.
|
||||
|
||||
In 1.5.1-1.5.x, anonymous access is disabled by default, and can be enabled by
|
||||
passing the `--anonymous-auth=true` option to the API server.
|
||||
|
||||
In 1.6+, anonymous access is enabled by default if an authorization mode other than `AlwaysAllow`
|
||||
is used, and can be disabled by passing the `--anonymous-auth=false` option to the API server.
|
||||
Starting in 1.6, the ABAC and RBAC authorizers require explicit authorization of the
|
||||
`system:anonymous` user or the `system:unauthenticated` group, so legacy policy rules
|
||||
that grant access to the `*` user or `*` group do not include anonymous users.
|
||||
|
||||
## User impersonation
|
||||
|
||||
A user can act as another user through impersonation headers. These let requests
|
||||
manually override the user info a request authenticates as. For example, an admin
|
||||
could use this feature to debug an authorization policy by temporarily
|
||||
impersonating another user and seeing if a request was denied.
|
||||
|
||||
Impersonation requests first authenticate as the requesting user, then switch
|
||||
to the impersonated user info.
|
||||
|
||||
* A user makes an API call with their credentials _and_ impersonation headers.
|
||||
* API server authenticates the user.
|
||||
* API server ensures the authenticated users has impersonation privileges.
|
||||
* Request user info is replaced with impersonation values.
|
||||
* Request is evaluated, authorization acts on impersonated user info.
|
||||
|
||||
The following HTTP headers can be used to performing an impersonation request:
|
||||
|
||||
* `Impersonate-User`: The username to act as.
|
||||
* `Impersonate-Group`: A group name to act as. Can be provided multiple times to set multiple groups. Optional. Requires "Impersonate-User"
|
||||
* `Impersonate-Extra-( extra name )`: A dynamic header used to associate extra fields with the user. Optional. Requires "Impersonate-User"
|
||||
|
||||
An example set of headers:
|
||||
|
||||
```http
|
||||
Impersonate-User: jane.doe@example.com
|
||||
Impersonate-Group: developers
|
||||
Impersonate-Group: admins
|
||||
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
|
||||
Impersonate-Extra-scopes: view
|
||||
Impersonate-Extra-scopes: development
|
||||
```
|
||||
|
||||
When using `kubectl` set the `--as` flag to configure the `Impersonate-User`
|
||||
header, set the `--as-group` flag to configure the `Impersonate-Group` header.
|
||||
|
||||
```shell
|
||||
$ kubectl drain mynode
|
||||
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)
|
||||
|
||||
$ kubectl drain mynode --as=superman --as-group=system:masters
|
||||
node "mynode" cordoned
|
||||
node "mynode" drained
|
||||
```
|
||||
|
||||
To impersonate a user, group, or set extra fields, the impersonating user must
|
||||
have the ability to perform the "impersonate" verb on the kind of attribute
|
||||
being impersonated ("user", "group", etc.). For clusters that enable the RBAC
|
||||
authorization plugin, the following ClusterRole encompasses the rules needed to
|
||||
set user and group impersonation headers:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: impersonator
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["users", "groups", "serviceaccounts"]
|
||||
verbs: ["impersonate"]
|
||||
```
|
||||
|
||||
Extra fields are evaluated as sub-resources of the resource "userextras". To
|
||||
allow a user to use impersonation headers for the extra field "scopes," a user
|
||||
should be granted the following role:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: scopes-impersonator
|
||||
rules:
|
||||
# Can set "Impersonate-Extra-scopes" header.
|
||||
- apiGroups: ["authentication.k8s.io"]
|
||||
resources: ["userextras/scopes"]
|
||||
verbs: ["impersonate"]
|
||||
```
|
||||
|
||||
The values of impersonation headers can also be restricted by limiting the set
|
||||
of `resourceNames` a resource can take.
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: limited-impersonator
|
||||
rules:
|
||||
# Can impersonate the user "jane.doe@example.com"
|
||||
- apiGroups: [""]
|
||||
resources: ["users"]
|
||||
verbs: ["impersonate"]
|
||||
resourceNames: ["jane.doe@example.com"]
|
||||
|
||||
# Can impersonate the groups "developers" and "admins"
|
||||
- apiGroups: [""]
|
||||
resources: ["groups"]
|
||||
verbs: ["impersonate"]
|
||||
resourceNames: ["developers","admins"]
|
||||
|
||||
# Can impersonate the extras field "scopes" with the values "view" and "development"
|
||||
- apiGroups: ["authentication.k8s.io"]
|
||||
resources: ["userextras/scopes"]
|
||||
verbs: ["impersonate"]
|
||||
resourceNames: ["view", "development"]
|
||||
```
|
||||
|
||||
## client-go credential plugins
|
||||
|
||||
{{< feature-state for_k8s_version="v1.10" state="alpha" >}}
|
||||
|
||||
`k8s.io/client-go` and tools using it such as `kubectl` and `kubelet` are able to execute an
|
||||
external command to receive user credentials.
|
||||
|
||||
This feature is intended for client side integrations with authentication protocols not natively
|
||||
supported by `k8s.io/client-go` (LDAP, Kerberos, OAuth2, SAML, etc.). The plugin implements the
|
||||
protocol specific logic, then returns opaque credentials to use. Almost all credential plugin
|
||||
use cases require a server side component with support for the [webhook token authenticator](#webhook-token-authentication)
|
||||
to interpret the credential format produced by the client plugin.
|
||||
|
||||
As of 1.10 only bearer tokens are supported. Support for client certs may be added in a future release.
|
||||
|
||||
### Example use case
|
||||
|
||||
In a hypothetical use case, an organization would run an external service that exchanges LDAP credentials
|
||||
for user specific, signed tokens. The service would also be capable of responding to [webhook token
|
||||
authenticator](#webhook-token-authentication) requests to validate the tokens. Users would be required
|
||||
to install a credential plugin on their workstation.
|
||||
|
||||
To authenticate against the API:
|
||||
|
||||
* The user issues a `kubectl` command.
|
||||
* Credential plugin prompts the user for LDAP credentials, exchanges credentials with external service for a token.
|
||||
* Credential plugin returns token to client-go, which uses it as a bearer token against the API server.
|
||||
* API server uses the [webhook token authenticator](#webhook-token-authentication) to submit a `TokenReview` to the external service.
|
||||
* External service verifies the signature on the token and returns the user's username and groups.
|
||||
|
||||
### Configuration
|
||||
|
||||
Credential plugins are configured through [`kubectl` config files](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)
|
||||
as part of the user fields.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
users:
|
||||
- name: my-user
|
||||
user:
|
||||
exec:
|
||||
# Command to execute. Required.
|
||||
command: "example-client-go-exec-plugin"
|
||||
|
||||
# API version to use when encoding and decoding the ExecCredentials
|
||||
# resource. Required.
|
||||
#
|
||||
# The API version returned by the plugin MUST match the version encoded.
|
||||
apiVersion: "client.authentication.k8s.io/v1alpha1"
|
||||
|
||||
# Environment variables to set when executing the plugin. Optional.
|
||||
env:
|
||||
- name: "FOO"
|
||||
value: "bar"
|
||||
|
||||
# Arguments to pass when executing the plugin. Optional.
|
||||
args:
|
||||
- "arg1"
|
||||
- "arg2"
|
||||
clusters:
|
||||
- name: my-cluster
|
||||
cluster:
|
||||
server: "https://172.17.4.100:6443"
|
||||
certificate-authority: "/etc/kubernetes/ca.pem"
|
||||
contexts:
|
||||
- name: my-cluster
|
||||
context:
|
||||
cluster: my-cluster
|
||||
user: my-user
|
||||
current-context: my-cluster
|
||||
```
|
||||
|
||||
Relative command paths are interpreted as relative to the directory of the config file. If
|
||||
KUBECONFIG is set to `/home/jane/kubeconfig` and the exec command is `./bin/example-client-go-exec-plugin`,
|
||||
the binary `/home/jane/bin/example-client-go-exec-plugin` is executed.
|
||||
|
||||
```yaml
|
||||
- name: my-user
|
||||
user:
|
||||
exec:
|
||||
# Path relative to the directory of the kubeconfig
|
||||
command: "./bin/example-client-go-exec-plugin"
|
||||
apiVersion: "client.authentication.k8s.io/v1alpha1"
|
||||
```
|
||||
|
||||
### Input and output formats
|
||||
|
||||
When executing the command, `k8s.io/client-go` sets the `KUBERNETES_EXEC_INFO` environment
|
||||
variable to a JSON serialized [`ExecCredential`](
|
||||
https://github.com/kubernetes/client-go/blob/master/pkg/apis/clientauthentication/v1alpha1/types.go)
|
||||
resource.
|
||||
|
||||
```
|
||||
KUBERNETES_EXEC_INFO='{
|
||||
"apiVersion": "client.authentication.k8s.io/v1alpha1",
|
||||
"kind": "ExecCredential",
|
||||
"spec": {
|
||||
"interactive": true
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
When plugins are executed from an interactive session, `stdin` and `stderr` are directly
|
||||
exposed to the plugin so it can prompt the user for input for interactive logins.
|
||||
|
||||
When responding to a 401 HTTP status code (indicating invalid credentials), this object will
|
||||
include metadata about the response.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "client.authentication.k8s.io/v1alpha1",
|
||||
"kind": "ExecCredential",
|
||||
"spec": {
|
||||
"response": {
|
||||
"code": 401,
|
||||
"header": {
|
||||
"WWW-Authenticate": [
|
||||
"Bearer realm=ldap.example.com"
|
||||
]
|
||||
},
|
||||
},
|
||||
"interactive": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The executed command is expected to print an `ExceCredential` to `stdout`. `k8s.io/client-go`
|
||||
will then use the returned bearer token in the `status` when authenticating against the
|
||||
Kubernetes API.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "client.authentication.k8s.io/v1alpha1",
|
||||
"kind": "ExecCredential",
|
||||
"status": {
|
||||
"token": "my-bearer-token"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Optionally, this output can include the expiry of the token formatted as a RFC3339 timestamp.
|
||||
If an expiry is omitted, the bearer token is cached until the server responds with a 401 HTTP
|
||||
status code. Note that this caching is only for the duration of process and therefore the plugin
|
||||
is triggered each time the tool using the plugin is invoked.
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "client.authentication.k8s.io/v1alpha1",
|
||||
"kind": "ExecCredential",
|
||||
"status": {
|
||||
"token": "my-bearer-token",
|
||||
"expirationTimestamp": "2018-03-05T17:30:20-08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
reviewers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Overview
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
Learn more about Kubernetes authorization, including details about creating
|
||||
policies using the supported authorization modules.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
In Kubernetes, you must be authenticated (logged in) before your request can be
|
||||
authorized (granted permission to access). For information about authentication,
|
||||
see [Accessing Control Overview](/docs/admin/accessing-the-api/).
|
||||
|
||||
Kubernetes expects attributes that are common to REST API requests. This means
|
||||
that Kubernetes authorization works with existing organization-wide or
|
||||
cloud-provider-wide access control systems which may handle other APIs besides
|
||||
the Kubernetes API.
|
||||
|
||||
## Determine Whether a Request is Allowed or Denied
|
||||
Kubernetes authorizes API requests using the API server. It evaluates all of the
|
||||
request attributes against all policies and allows or denies the request. All
|
||||
parts of an API request must be allowed by some policy in order to proceed. This
|
||||
means that permissions are denied by default.
|
||||
|
||||
(Although Kubernetes uses the API server, access controls and policies that
|
||||
depend on specific fields of specific kinds of objects are handled by Admission
|
||||
Controllers.)
|
||||
|
||||
When multiple authorization modules are configured, each is checked in sequence.
|
||||
If any authorizer approves or denies a request, that decision is immediately
|
||||
returned and no other authorizer is consulted. If all modules have no opinion on
|
||||
the request, then the request is denied. A deny returns an HTTP status code 403.
|
||||
|
||||
## Review Your Request Attributes
|
||||
Kubernetes reviews only the following API request attributes:
|
||||
|
||||
* **user** - The `user` string provided during authentication.
|
||||
* **group** - The list of group names to which the authenticated user belongs.
|
||||
* **"extra"** - A map of arbitrary string keys to string values, provided by the authentication layer.
|
||||
* **API** - Indicates whether the request is for an API resource.
|
||||
* **Request path** - Path to miscellaneous non-resource endpoints like `/api` or `/healthz`.
|
||||
* **API request verb** - API verbs `get`, `list`, `create`, `update`, `patch`, `watch`, `proxy`, `redirect`, `delete`, and `deletecollection` are used for resource requests. To determine the request verb for a resource API endpoint, see **Determine the request verb** below.
|
||||
* **HTTP request verb** - HTTP verbs `get`, `post`, `put`, and `delete` are used for non-resource requests.
|
||||
* **Resource** - The ID or name of the resource that is being accessed (for resource requests only) -- For resource requests using `get`, `update`, `patch`, and `delete` verbs, you must provide the resource name.
|
||||
* **Subresource** - The subresource that is being accessed (for resource requests only).
|
||||
* **Namespace** - The namespace of the object that is being accessed (for namespaced resource requests only).
|
||||
* **API group** - The API group being accessed (for resource requests only). An empty string designates the [core API group](/docs/concepts/overview/kubernetes-api/).
|
||||
|
||||
## Determine the Request Verb
|
||||
To determine the request verb for a resource API endpoint, review the HTTP verb
|
||||
used and whether or not the request acts on an individual resource or a
|
||||
collection of resources:
|
||||
|
||||
HTTP verb | request verb
|
||||
----------|---------------
|
||||
POST | create
|
||||
GET, HEAD | get (for individual resources), list (for collections)
|
||||
PUT | update
|
||||
PATCH | patch
|
||||
DELETE | delete (for individual resources), deletecollection (for collections)
|
||||
|
||||
Kubernetes sometimes checks authorization for additional permissions using specialized verbs. For example:
|
||||
|
||||
* [PodSecurityPolicy](/docs/concepts/policy/pod-security-policy/) checks for authorization of the `use` verb on `podsecuritypolicies` resources in the `policy` API group.
|
||||
* [RBAC](/docs/admin/authorization/rbac/#privilege-escalation-prevention-and-bootstrapping) checks for authorization
|
||||
of the `bind` verb on `roles` and `clusterroles` resources in the `rbac.authorization.k8s.io` API group.
|
||||
* [Authentication](/docs/admin/authentication/) layer checks for authorization of the `impersonate` verb on `users`, `groups`, and `serviceaccounts` in the core API group, and the `userextras` in the `authentication.k8s.io` API group.
|
||||
|
||||
## Authorization Modules
|
||||
* **Node** - A special-purpose authorizer that grants permissions to kubelets based on the pods they are scheduled to run. To learn more about using the Node authorization mode, see [Node Authorization](/docs/admin/authorization/node/).
|
||||
* **ABAC** - Attribute-based access control (ABAC) defines an access control paradigm whereby access rights are granted to users through the use of policies which combine attributes together. The policies can use any type of attributes (user attributes, resource attributes, object, environment attributes, etc). To learn more about using the ABAC mode, see [ABAC Mode](/docs/admin/authorization/abac/).
|
||||
* **RBAC** - Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within an enterprise. In this context, access is the ability of an individual user to perform a specific task, such as view, create, or modify a file. To learn more about using the RBAC mode, see [RBAC Mode](/docs/admin/authorization/rbac/)
|
||||
* When specified "RBAC" (Role-Based Access Control) uses the "rbac.authorization.k8s.io" API group to drive authorization decisions, allowing admins to dynamically configure permission policies through the Kubernetes API.
|
||||
* To enable RBAC, start the apiserver with `--authorization-mode=RBAC`.
|
||||
* **Webhook** - A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen. To learn more about using the Webhook mode, see [Webhook Mode](/docs/admin/authorization/webhook/).
|
||||
|
||||
#### Checking API Access
|
||||
|
||||
`kubectl` provides the `auth can-i` subcommand for quickly querying the API authorization layer.
|
||||
The command uses the `SelfSubjectAccessReview` API to determine if the current user can perform
|
||||
a given action, and works regardless of the authorization mode used.
|
||||
|
||||
|
||||
```bash
|
||||
$ kubectl auth can-i create deployments --namespace dev
|
||||
yes
|
||||
$ kubectl auth can-i create deployments --namespace prod
|
||||
no
|
||||
```
|
||||
|
||||
Administrators can combine this with ["user impersonation"](/docs/admin/authentication/#user-impersonation)
|
||||
to determine what action other users can perform.
|
||||
|
||||
```bash
|
||||
$ kubectl auth can-i list secrets --namespace dev --as dave
|
||||
no
|
||||
```
|
||||
|
||||
`SelfSubjectAccessReview` is part of the `authorization.k8s.io` API group, which
|
||||
exposes the API server authorization to external services. Other resources in
|
||||
this group include:
|
||||
|
||||
* `SubjectAccessReview` - Access review for any user, not just the current one. Useful for delegating authorization decisions to the API server. For example, the kubelet and extension API servers use this to determine user access to their own APIs.
|
||||
* `LocalSubjectAccessReview` - Like `SubjectAccessReview` but restricted to a specific namespace.
|
||||
* `SelfSubjectRulesReview` - A review which returns the set of actions a user can perform within a namespace. Useful for users to quickly summarize their own access, or for UIs to hide/show actions.
|
||||
|
||||
These APIs can be queried by creating normal Kubernetes resources, where the response "status"
|
||||
field of the returned object is the result of the query.
|
||||
|
||||
```bash
|
||||
$ kubectl create -f - -o yaml << EOF
|
||||
apiVersion: authorization.k8s.io/v1
|
||||
kind: SelfSubjectAccessReview
|
||||
spec:
|
||||
resourceAttributes:
|
||||
group: apps
|
||||
name: deployments
|
||||
verb: create
|
||||
namespace: dev
|
||||
EOF
|
||||
|
||||
apiVersion: authorization.k8s.io/v1
|
||||
kind: SelfSubjectAccessReview
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
spec:
|
||||
resourceAttributes:
|
||||
group: apps
|
||||
name: deployments
|
||||
namespace: dev
|
||||
verb: create
|
||||
status:
|
||||
allowed: true
|
||||
denied: false
|
||||
```
|
||||
|
||||
## Using Flags for Your Authorization Module
|
||||
|
||||
You must include a flag in your policy to indicate which authorization module
|
||||
your policies include:
|
||||
|
||||
The following flags can be used:
|
||||
|
||||
* `--authorization-mode=ABAC` Attribute-Based Access Control (ABAC) mode allows you to configure policies using local files.
|
||||
* `--authorization-mode=RBAC` Role-based access control (RBAC) mode allows you to create and store policies using the Kubernetes API.
|
||||
* `--authorization-mode=Webhook` WebHook is an HTTP callback mode that allows you to manage authorization using a remote REST endpoint.
|
||||
* `--authorization-mode=Node` Node authorization is a special-purpose authorization mode that specifically authorizes API requests made by kubelets.
|
||||
* `--authorization-mode=AlwaysDeny` This flag blocks all requests. Use this flag only for testing.
|
||||
* `--authorization-mode=AlwaysAllow` This flag allows all requests. Use this flag only if you do not require authorization for your API requests.
|
||||
|
||||
You can choose more than one authorization module. Modules are checked in order
|
||||
so an earlier module has higher priority to allow or deny a request.
|
||||
|
||||
{{% /capture %}}
|
||||
{{% capture whatsnext %}}
|
||||
* To learn more about Authentication, see **Authentication** in [Controlling Access to the Kubernetes API](/docs/admin/accessing-the-api/).
|
||||
* To learn more about Admission Control, see [Using Admission Controllers](/docs/admin/admission-controllers/).
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
## Privilege escalation via pod creation
|
||||
|
||||
Users who have the ability to create pods in a namespace can potentially
|
||||
escalate their privileges within that namespace. They can create pods that
|
||||
access their privileges within that namespace. They can create pods that access
|
||||
secrets the user cannot themselves read, or that run under a service account
|
||||
with different/greater permissions.
|
||||
|
||||
{{< caution >}}
|
||||
**Caution:** System administrators, use care when granting access to pod
|
||||
creation. A user granted permission to create pods (or controllers that create
|
||||
pods) in the namespace can: read all secrets in the namespace; read all config
|
||||
maps in the namespace; and impersonate any service account in the namespace and
|
||||
take any action the account could take. This applies regardless of authorization
|
||||
mode.
|
||||
{{< /caution >}}
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
reviewers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: ABAC Mode
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
Attribute-based access control (ABAC) defines an access control paradigm whereby access rights are granted to users through the use of policies which combine attributes together.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
## Policy File Format
|
||||
|
||||
For mode `ABAC`, also specify `--authorization-policy-file=SOME_FILENAME`.
|
||||
|
||||
The file format is [one JSON object per line](http://jsonlines.org/). There
|
||||
should be no enclosing list or map, just one map per line.
|
||||
|
||||
Each line is a "policy object". A policy object is a map with the following
|
||||
properties:
|
||||
|
||||
- Versioning properties:
|
||||
- `apiVersion`, type string; valid values are "abac.authorization.kubernetes.io/v1beta1". Allows versioning and conversion of the policy format.
|
||||
- `kind`, type string: valid values are "Policy". Allows versioning and conversion of the policy format.
|
||||
- `spec` property set to a map with the following properties:
|
||||
- Subject-matching properties:
|
||||
- `user`, type string; the user-string from `--token-auth-file`. If you specify `user`, it must match the username of the authenticated user.
|
||||
- `group`, type string; if you specify `group`, it must match one of the groups of the authenticated user. `system:authenticated` matches all authenticated requests. `system:unauthenticated` matches all unauthenticated requests.
|
||||
- Resource-matching properties:
|
||||
- `apiGroup`, type string; an API group.
|
||||
- Ex: `extensions`
|
||||
- Wildcard: `*` matches all API groups.
|
||||
- `namespace`, type string; a namespace.
|
||||
- Ex: `kube-system`
|
||||
- Wildcard: `*` matches all resource requests.
|
||||
- `resource`, type string; a resource type
|
||||
- Ex: `pods`
|
||||
- Wildcard: `*` matches all resource requests.
|
||||
- Non-resource-matching properties:
|
||||
- `nonResourcePath`, type string; non-resource request paths.
|
||||
- Ex: `/version` or `/apis`
|
||||
- Wildcard:
|
||||
- `*` matches all non-resource requests.
|
||||
- `/foo/*` matches all subpaths of `/foo/`.
|
||||
- `readonly`, type boolean, when true, means that the Resource-matching policy only applies to get, list, and watch operations, Non-resource-matching policy only applies to get operation.
|
||||
|
||||
**NOTES:** An unset property is the same as a property set to the zero value for its type
|
||||
(e.g. empty string, 0, false). However, unset should be preferred for
|
||||
readability.
|
||||
|
||||
In the future, policies may be expressed in a JSON format, and managed via a
|
||||
REST interface.
|
||||
|
||||
## Authorization Algorithm
|
||||
|
||||
A request has attributes which correspond to the properties of a policy object.
|
||||
|
||||
When a request is received, the attributes are determined. Unknown attributes
|
||||
are set to the zero value of its type (e.g. empty string, 0, false).
|
||||
|
||||
A property set to `"*"` will match any value of the corresponding attribute.
|
||||
|
||||
The tuple of attributes is checked for a match against every policy in the
|
||||
policy file. If at least one line matches the request attributes, then the
|
||||
request is authorized (but may fail later validation).
|
||||
|
||||
To permit any authenticated user to do something, write a policy with the
|
||||
group property set to `"system:authenticated"`.
|
||||
|
||||
To permit any unauthenticated user to do something, write a policy with the
|
||||
group property set to `"system:unauthenticated"`.
|
||||
|
||||
To permit a user to do anything, write a policy with the apiGroup, namespace,
|
||||
resource, and nonResourcePath properties set to `"*"`.
|
||||
|
||||
## Kubectl
|
||||
|
||||
Kubectl uses the `/api` and `/apis` endpoints of api-server to negotiate
|
||||
client/server versions. To validate objects sent to the API by create/update
|
||||
operations, kubectl queries certain swagger resources. For API version `v1`
|
||||
those would be `/swaggerapi/api/v1` & `/swaggerapi/experimental/v1`.
|
||||
|
||||
When using ABAC authorization, those special resources have to be explicitly
|
||||
exposed via the `nonResourcePath` property in a policy (see [examples](#examples) below):
|
||||
|
||||
* `/api`, `/api/*`, `/apis`, and `/apis/*` for API version negotiation.
|
||||
* `/version` for retrieving the server version via `kubectl version`.
|
||||
* `/swaggerapi/*` for create/update operations.
|
||||
|
||||
To inspect the HTTP calls involved in a specific kubectl operation you can turn
|
||||
up the verbosity:
|
||||
|
||||
kubectl --v=8 version
|
||||
|
||||
## Examples
|
||||
|
||||
1. Alice can do anything to all resources:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}}
|
||||
```
|
||||
2. Kubelet can read any pods:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}}
|
||||
```
|
||||
3. Kubelet can read and write events:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}}
|
||||
```
|
||||
4. Bob can just read pods in namespace "projectCaribou":
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
|
||||
```
|
||||
5. Anyone can make read-only requests to all non-resource paths:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:authenticated", "readonly": true, "nonResourcePath": "*"}}
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:unauthenticated", "readonly": true, "nonResourcePath": "*"}}
|
||||
```
|
||||
|
||||
[Complete file example](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/auth/authorizer/abac/example_policy_file.jsonl)
|
||||
|
||||
## A quick note on service accounts
|
||||
|
||||
A service account automatically generates a user. The user's name is generated
|
||||
according to the naming convention:
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:<serviceaccountname>
|
||||
```
|
||||
Creating a new namespace also causes a new service account to be created, of
|
||||
this form:
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:default
|
||||
```
|
||||
|
||||
For example, if you wanted to grant the default service account in the
|
||||
kube-system full privilege to the API, you would add this line to your policy
|
||||
file:
|
||||
|
||||
```json
|
||||
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"system:serviceaccount:kube-system:default","namespace":"*","resource":"*","apiGroup":"*"}}
|
||||
```
|
||||
|
||||
The apiserver will need to be restarted to pickup the new policy lines.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
reviewers:
|
||||
- timstclair
|
||||
- deads2k
|
||||
- liggitt
|
||||
- ericchiang
|
||||
title: Using Node Authorization
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
Node authorization is a special-purpose authorization mode that specifically authorizes API requests made by kubelets.
|
||||
|
||||
## Overview
|
||||
|
||||
The Node authorizer allows a kubelet to perform API operations. This includes:
|
||||
|
||||
Read operations:
|
||||
|
||||
* services
|
||||
* endpoints
|
||||
* nodes
|
||||
* pods
|
||||
* secrets, configmaps, persistent volume claims and persistent volumes related to pods bound to the kubelet's node
|
||||
|
||||
Write operations:
|
||||
|
||||
* nodes and node status (enable the `NodeRestriction` admission plugin to limit a kubelet to modify its own node)
|
||||
* pods and pod status (enable the `NodeRestriction` admission plugin to limit a kubelet to modify pods bound to itself)
|
||||
* events
|
||||
|
||||
Auth-related operations:
|
||||
|
||||
* read/write access to the certificationsigningrequests API for TLS bootstrapping
|
||||
* the ability to create tokenreviews and subjectaccessreviews for delegated authentication/authorization checks
|
||||
|
||||
In future releases, the node authorizer may add or remove permissions to ensure kubelets
|
||||
have the minimal set of permissions required to operate correctly.
|
||||
|
||||
In order to be authorized by the Node authorizer, kubelets must use a credential that identifies them as
|
||||
being in the `system:nodes` group, with a username of `system:node:<nodeName>`.
|
||||
This group and user name format match the identity created for each kubelet as part of
|
||||
[kubelet TLS bootstrapping](/docs/admin/kubelet-tls-bootstrapping/).
|
||||
|
||||
To enable the Node authorizer, start the apiserver with `--authorization-mode=Node`.
|
||||
|
||||
To limit the API objects kubelets are able to write, enable the [NodeRestriction](/docs/admin/admission-controllers#NodeRestriction) admission plugin by starting the apiserver with `--enable-admission-plugins=...,NodeRestriction,...`
|
||||
|
||||
## Migration considerations
|
||||
|
||||
### Kubelets outside the `system:nodes` group
|
||||
|
||||
Kubelets outside the `system:nodes` group would not be authorized by the `Node` authorization mode,
|
||||
and would need to continue to be authorized via whatever mechanism currently authorizes them.
|
||||
The node admission plugin would not restrict requests from these kubelets.
|
||||
|
||||
### Kubelets with undifferentiated usernames
|
||||
|
||||
In some deployments, kubelets have credentials that place them in the `system:nodes` group,
|
||||
but do not identify the particular node they are associated with,
|
||||
because they do not have a username in the `system:node:...` format.
|
||||
These kubelets would not be authorized by the `Node` authorization mode,
|
||||
and would need to continue to be authorized via whatever mechanism currently authorizes them.
|
||||
|
||||
The `NodeRestriction` admission plugin would ignore requests from these kubelets,
|
||||
since the default node identifier implementation would not consider that a node identity.
|
||||
|
||||
### Upgrades from previous versions using RBAC
|
||||
|
||||
Upgraded pre-1.7 clusters using [RBAC](/docs/admin/authorization/rbac/) will continue functioning as-is because the `system:nodes` group binding will already exist.
|
||||
|
||||
If a cluster admin wishes to start using the `Node` authorizer and `NodeRestriction` admission plugin
|
||||
to limit node access to the API, that can be done non-disruptively:
|
||||
|
||||
1. Enable the `Node` authorization mode (`--authorization-mode=Node,RBAC`) and the `NodeRestriction` admission plugin
|
||||
2. Ensure all kubelets' credentials conform to the group/username requirements
|
||||
3. Audit apiserver logs to ensure the `Node` authorizer is not rejecting requests from kubelets (no persistent `NODE DENY` messages logged)
|
||||
4. Delete the `system:node` cluster role binding
|
||||
|
||||
### RBAC Node Permissions
|
||||
|
||||
In 1.6, the `system:node` cluster role was automatically bound to the `system:nodes` group when using the [RBAC Authorization mode](/docs/admin/authorization/rbac/).
|
||||
|
||||
In 1.7, the automatic binding of the `system:nodes` group to the `system:node` role is deprecated
|
||||
because the node authorizer accomplishes the same purpose with the benefit of additional restrictions
|
||||
on secret and configmap access. If the `Node` and `RBAC` authorization modes are both enabled,
|
||||
the automatic binding of the `system:nodes` group to the `system:node` role is not created in 1.7.
|
||||
|
||||
In 1.8, the binding will not be created at all.
|
||||
|
||||
When using RBAC, the `system:node` cluster role will continue to be created,
|
||||
for compatibility with deployment methods that bind other users or groups to that role.
|
||||
@@ -0,0 +1,872 @@
|
||||
---
|
||||
reviewers:
|
||||
- erictune
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Using RBAC Authorization
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
Role-Based Access Control ("RBAC") uses the "rbac.authorization.k8s.io" API group
|
||||
to drive authorization decisions, allowing admins to dynamically configure policies
|
||||
through the Kubernetes API.
|
||||
|
||||
As of 1.8, RBAC mode is stable and backed by the rbac.authorization.k8s.io/v1 API.
|
||||
|
||||
To enable RBAC, start the apiserver with `--authorization-mode=RBAC`.
|
||||
|
||||
## API Overview
|
||||
|
||||
The RBAC API declares four top-level types which will be covered in this
|
||||
section. Users can interact with these resources as they would with any other
|
||||
API resource (via `kubectl`, API calls, etc.). For instance,
|
||||
`kubectl create -f (resource).yml` can be used with any of these examples,
|
||||
though readers who wish to follow along should review the section on
|
||||
bootstrapping first.
|
||||
|
||||
### Role and ClusterRole
|
||||
|
||||
In the RBAC API, a role contains rules that represent a set of permissions.
|
||||
Permissions are purely additive (there are no "deny" rules).
|
||||
A role can be defined within a namespace with a `Role`, or cluster-wide with a `ClusterRole`.
|
||||
|
||||
A `Role` can only be used to grant access to resources within a single namespace.
|
||||
Here's an example `Role` in the "default" namespace that can be used to grant read access to pods:
|
||||
|
||||
```yaml
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: default
|
||||
name: pod-reader
|
||||
rules:
|
||||
- apiGroups: [""] # "" indicates the core API group
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
```
|
||||
|
||||
A `ClusterRole` can be used to grant the same permissions as a `Role`,
|
||||
but because they are cluster-scoped, they can also be used to grant access to:
|
||||
|
||||
* cluster-scoped resources (like nodes)
|
||||
* non-resource endpoints (like "/healthz")
|
||||
* namespaced resources (like pods) across all namespaces (needed to run `kubectl get pods --all-namespaces`, for example)
|
||||
|
||||
The following `ClusterRole` can be used to grant read access to secrets in any particular namespace,
|
||||
or across all namespaces (depending on how it is [bound](#rolebinding-and-clusterrolebinding)):
|
||||
|
||||
```yaml
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
# "namespace" omitted since ClusterRoles are not namespaced
|
||||
name: secret-reader
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
```
|
||||
|
||||
### RoleBinding and ClusterRoleBinding
|
||||
|
||||
A role binding grants the permissions defined in a role to a user or set of users.
|
||||
It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted.
|
||||
Permissions can be granted within a namespace with a `RoleBinding`, or cluster-wide with a `ClusterRoleBinding`.
|
||||
|
||||
A `RoleBinding` may reference a `Role` in the same namespace.
|
||||
The following `RoleBinding` grants the "pod-reader" role to the user "jane" within the "default" namespace.
|
||||
This allows "jane" to read pods in the "default" namespace.
|
||||
|
||||
```yaml
|
||||
# This role binding allows "jane" to read pods in the "default" namespace.
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: read-pods
|
||||
namespace: default
|
||||
subjects:
|
||||
- kind: User
|
||||
name: jane # Name is case sensitive
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: pod-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
A `RoleBinding` may also reference a `ClusterRole` to grant the permissions to namespaced
|
||||
resources defined in the `ClusterRole` within the `RoleBinding`'s namespace.
|
||||
This allows administrators to define a set of common roles for the entire cluster,
|
||||
then reuse them within multiple namespaces.
|
||||
|
||||
For instance, even though the following `RoleBinding` refers to a `ClusterRole`,
|
||||
"dave" (the subject, case sensitive) will only be able to read secrets in the "development"
|
||||
namespace (the namespace of the `RoleBinding`).
|
||||
|
||||
```yaml
|
||||
# This role binding allows "dave" to read secrets in the "development" namespace.
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: read-secrets
|
||||
namespace: development # This only grants permissions within the "development" namespace.
|
||||
subjects:
|
||||
- kind: User
|
||||
name: dave # Name is case sensitive
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: secret-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
Finally, a `ClusterRoleBinding` may be used to grant permission at the cluster level and in all
|
||||
namespaces. The following `ClusterRoleBinding` allows any user in the group "manager" to read
|
||||
secrets in any namespace.
|
||||
|
||||
```yaml
|
||||
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: read-secrets-global
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: manager # Name is case sensitive
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: secret-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
### Referring to Resources
|
||||
|
||||
Most resources are represented by a string representation of their name, such as "pods", just as it
|
||||
appears in the URL for the relevant API endpoint. However, some Kubernetes APIs involve a
|
||||
"subresource", such as the logs for a pod. The URL for the pods logs endpoint is:
|
||||
|
||||
```
|
||||
GET /api/v1/namespaces/{namespace}/pods/{name}/log
|
||||
```
|
||||
|
||||
In this case, "pods" is the namespaced resource, and "log" is a subresource of pods. To represent
|
||||
this in an RBAC role, use a slash to delimit the resource and subresource. To allow a subject
|
||||
to read both pods and pod logs, you would write:
|
||||
|
||||
```yaml
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: default
|
||||
name: pod-and-pod-logs-reader
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list"]
|
||||
```
|
||||
|
||||
Resources can also be referred to by name for certain requests through the `resourceNames` list.
|
||||
When specified, requests using the "get", "delete", "update", and "patch" verbs can be restricted
|
||||
to individual instances of a resource. To restrict a subject to only "get" and "update" a single
|
||||
configmap, you would write:
|
||||
|
||||
```yaml
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
namespace: default
|
||||
name: configmap-updater
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps"]
|
||||
resourceNames: ["my-configmap"]
|
||||
verbs: ["update", "get"]
|
||||
```
|
||||
|
||||
Notably, if `resourceNames` are set, then the verb must not be list, watch, create, or deletecollection.
|
||||
Because resource names are not present in the URL for create, list, watch, and deletecollection API requests,
|
||||
those verbs would not be allowed by a rule with `resourceNames` set, since the `resourceNames` portion of the
|
||||
rule would not match the request.
|
||||
|
||||
### Aggregated ClusterRoles
|
||||
|
||||
As of 1.9, ClusterRoles can be created by combining other ClusterRoles using an `aggregationRule`. The
|
||||
permissions of aggregated ClusterRoles are controller-managed, and filled in by unioning the rules of any
|
||||
ClusterRole that matches the provided label selector. An example aggregated ClusterRole:
|
||||
|
||||
```yaml
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: monitoring
|
||||
aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.example.com/aggregate-to-monitoring: "true"
|
||||
rules: [] # Rules are automatically filled in by the controller manager.
|
||||
```
|
||||
|
||||
Creating a ClusterRole that matches the label selector will add rules to the aggregated ClusterRole. In this case
|
||||
rules can be added to the "monitoring" ClusterRole by creating another ClusterRole that has the label
|
||||
`rbac.example.com/aggregate-to-monitoring: true`.
|
||||
|
||||
```yaml
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: monitoring-endpoints
|
||||
labels:
|
||||
rbac.example.com/aggregate-to-monitoring: "true"
|
||||
# These rules will be added to the "monitoring" role.
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
Resources: ["services", "endpoints", "pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
|
||||
The default user-facing roles (described below) use ClusterRole aggregation. This lets admins include rules
|
||||
for custom resources, such as those served by CustomResourceDefinitions or Aggregated API servers, on the
|
||||
default roles.
|
||||
|
||||
For example, the following ClusterRoles let the "admin" and "edit" default roles manage the custom resource
|
||||
"CronTabs" and the "view" role perform read-only actions on the resource.
|
||||
|
||||
```yaml
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: aggregate-cron-tabs-edit
|
||||
labels:
|
||||
# Add these permissions to the "admin" and "edit" default roles.
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
rules:
|
||||
- apiGroups: ["stable.example.com"]
|
||||
resources: ["crontabs"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
---
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: aggregate-cron-tabs-view
|
||||
labels:
|
||||
# Add these permissions to the "view" default role.
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
rules:
|
||||
- apiGroups: ["stable.example.com"]
|
||||
resources: ["crontabs"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
|
||||
#### Role Examples
|
||||
|
||||
Only the `rules` section is shown in the following examples.
|
||||
|
||||
Allow reading the resource "pods" in the core API group:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
|
||||
Allow reading/writing "deployments" in both the "extensions" and "apps" API groups:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: ["extensions", "apps"]
|
||||
resources: ["deployments"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
```
|
||||
|
||||
Allow reading "pods" and reading/writing "jobs":
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["batch", "extensions"]
|
||||
resources: ["jobs"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
```
|
||||
|
||||
Allow reading a `ConfigMap` named "my-config" (must be bound with a `RoleBinding` to limit to a single `ConfigMap` in a single namespace):
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps"]
|
||||
resourceNames: ["my-config"]
|
||||
verbs: ["get"]
|
||||
```
|
||||
|
||||
Allow reading the resource "nodes" in the core group (because a `Node` is cluster-scoped, this must be in a `ClusterRole` bound with a `ClusterRoleBinding` to be effective):
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["nodes"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
```
|
||||
|
||||
Allow "GET" and "POST" requests to the non-resource endpoint "/healthz" and all subpaths (must be in a `ClusterRole` bound with a `ClusterRoleBinding` to be effective):
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- nonResourceURLs: ["/healthz", "/healthz/*"] # '*' in a nonResourceURL is a suffix glob match
|
||||
verbs: ["get", "post"]
|
||||
```
|
||||
|
||||
### Referring to Subjects
|
||||
|
||||
A `RoleBinding` or `ClusterRoleBinding` binds a role to *subjects*.
|
||||
Subjects can be groups, users or service accounts.
|
||||
|
||||
Users are represented by strings. These can be plain usernames, like
|
||||
"alice", email-style names, like "bob@example.com", or numeric IDs
|
||||
represented as a string. It is up to the Kubernetes admin to configure
|
||||
the [authentication modules](/docs/admin/authentication/) to produce
|
||||
usernames in the desired format. The RBAC authorization system does
|
||||
not require any particular format. However, the prefix `system:` is
|
||||
reserved for Kubernetes system use, and so the admin should ensure
|
||||
usernames do not contain this prefix by accident.
|
||||
|
||||
Group information in Kubernetes is currently provided by the Authenticator
|
||||
modules. Groups, like users, are represented as strings, and that string
|
||||
has no format requirements, other than that the prefix `system:` is reserved.
|
||||
|
||||
[Service Accounts](/docs/tasks/configure-pod-container/configure-service-account/) have usernames with the `system:serviceaccount:` prefix and belong
|
||||
to groups with the `system:serviceaccounts:` prefix.
|
||||
|
||||
#### Role Binding Examples
|
||||
|
||||
Only the `subjects` section of a `RoleBinding` is shown in the following examples.
|
||||
|
||||
For a user named "alice@example.com":
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: User
|
||||
name: "alice@example.com"
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For a group named "frontend-admins":
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: "frontend-admins"
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For the default service account in the kube-system namespace:
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: kube-system
|
||||
```
|
||||
|
||||
For all service accounts in the "qa" namespace:
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:serviceaccounts:qa
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For all service accounts everywhere:
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:serviceaccounts
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For all authenticated users (version 1.5+):
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For all unauthenticated users (version 1.5+):
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:unauthenticated
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
For all users (version 1.5+):
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
- kind: Group
|
||||
name: system:unauthenticated
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
## Default Roles and Role Bindings
|
||||
|
||||
API servers create a set of default `ClusterRole` and `ClusterRoleBinding` objects.
|
||||
Many of these are `system:` prefixed, which indicates that the resource is "owned" by the infrastructure.
|
||||
Modifications to these resources can result in non-functional clusters. One example is the `system:node` ClusterRole.
|
||||
This role defines permissions for kubelets. If the role is modified, it can prevent kubelets from working.
|
||||
|
||||
All of the default cluster roles and rolebindings are labeled with `kubernetes.io/bootstrapping=rbac-defaults`.
|
||||
|
||||
### Auto-reconciliation
|
||||
|
||||
At each start-up, the API server updates default cluster roles with any missing permissions,
|
||||
and updates default cluster role bindings with any missing subjects.
|
||||
This allows the cluster to repair accidental modifications,
|
||||
and to keep roles and rolebindings up-to-date as permissions and subjects change in new releases.
|
||||
|
||||
To opt out of this reconciliation, set the `rbac.authorization.kubernetes.io/autoupdate`
|
||||
annotation on a default cluster role or rolebinding to `false`.
|
||||
Be aware that missing default permissions and subjects can result in non-functional clusters.
|
||||
|
||||
Auto-reconciliation is enabled in Kubernetes version 1.6+ when the RBAC authorizer is active.
|
||||
|
||||
### Discovery Roles
|
||||
|
||||
<table>
|
||||
<colgroup><col width="25%"><col width="25%"><col></colgroup>
|
||||
<tr>
|
||||
<th>Default ClusterRole</th>
|
||||
<th>Default ClusterRoleBinding</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:basic-user</b></td>
|
||||
<td><b>system:authenticated</b> and <b>system:unauthenticated</b> groups</td>
|
||||
<td>Allows a user read-only access to basic information about themselves.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:discovery</b></td>
|
||||
<td><b>system:authenticated</b> and <b>system:unauthenticated</b> groups</td>
|
||||
<td>Allows read-only access to API discovery endpoints needed to discover and negotiate an API level.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### User-facing Roles
|
||||
|
||||
Some of the default roles are not `system:` prefixed. These are intended to be user-facing roles.
|
||||
They include super-user roles (`cluster-admin`),
|
||||
roles intended to be granted cluster-wide using ClusterRoleBindings (`cluster-status`),
|
||||
and roles intended to be granted within particular namespaces using RoleBindings (`admin`, `edit`, `view`).
|
||||
|
||||
As of 1.9, user-facing roles use [ClusterRole Aggregation](#aggregated-clusterroles) to allow admins to include
|
||||
rules for custom resources on these roles. To add rules to the "admin", "edit", or "view" role, create a
|
||||
ClusterRole with one or more of the following labels:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
labels:
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
```
|
||||
|
||||
<table>
|
||||
<colgroup><col width="25%"><col width="25%"><col></colgroup>
|
||||
<tr>
|
||||
<th>Default ClusterRole</th>
|
||||
<th>Default ClusterRoleBinding</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>cluster-admin</b></td>
|
||||
<td><b>system:masters</b> group</td>
|
||||
<td>Allows super-user access to perform any action on any resource.
|
||||
When used in a <b>ClusterRoleBinding</b>, it gives full control over every resource in the cluster and in all namespaces.
|
||||
When used in a <b>RoleBinding</b>, it gives full control over every resource in the rolebinding's namespace, including the namespace itself.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>admin</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows admin access, intended to be granted within a namespace using a <b>RoleBinding</b>.
|
||||
If used in a <b>RoleBinding</b>, allows read/write access to most resources in a namespace,
|
||||
including the ability to create roles and rolebindings within the namespace.
|
||||
It does not allow write access to resource quota or to the namespace itself.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>edit</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows read/write access to most objects in a namespace.
|
||||
It does not allow viewing or modifying roles or rolebindings.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>view</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows read-only access to see most objects in a namespace.
|
||||
It does not allow viewing roles or rolebindings.
|
||||
It does not allow viewing secrets, since those are escalating.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Core Component Roles
|
||||
|
||||
<table>
|
||||
<colgroup><col width="25%"><col width="25%"><col></colgroup>
|
||||
<tr>
|
||||
<th>Default ClusterRole</th>
|
||||
<th>Default ClusterRoleBinding</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:kube-scheduler</b></td>
|
||||
<td><b>system:kube-scheduler</b> user</td>
|
||||
<td>Allows access to the resources required by the kube-scheduler component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:kube-controller-manager</b></td>
|
||||
<td><b>system:kube-controller-manager</b> user</td>
|
||||
<td>Allows access to the resources required by the kube-controller-manager component.
|
||||
The permissions required by individual control loops are contained in the <a href="#controller-roles">controller roles</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:node</b></td>
|
||||
<td>None in 1.8+</td>
|
||||
<td>Allows access to resources required by the kubelet component, <b>including read access to all secrets, and write access to all pod status objects</b>.
|
||||
As of 1.7, use of the <a href="/docs/admin/authorization/node/">Node authorizer</a> and <a href="/docs/admin/admission-controllers/#noderestriction">NodeRestriction admission plugin</a> is recommended instead of this role, and allow granting API access to kubelets based on the pods scheduled to run on them.
|
||||
Prior to 1.7, this role was automatically bound to the `system:nodes` group.
|
||||
In 1.7, this role was automatically bound to the `system:nodes` group if the `Node` authorization mode is not enabled.
|
||||
In 1.8+, no binding is automatically created.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:node-proxier</b></td>
|
||||
<td><b>system:kube-proxy</b> user</td>
|
||||
<td>Allows access to the resources required by the kube-proxy component.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Other Component Roles
|
||||
|
||||
<table>
|
||||
<colgroup><col width="25%"><col width="25%"><col></colgroup>
|
||||
<tr>
|
||||
<th>Default ClusterRole</th>
|
||||
<th>Default ClusterRoleBinding</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:auth-delegator</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows delegated authentication and authorization checks.
|
||||
This is commonly used by add-on API servers for unified authentication and authorization.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:heapster</b></td>
|
||||
<td>None</td>
|
||||
<td>Role for the <a href="https://github.com/kubernetes/heapster">Heapster</a> component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:kube-aggregator</b></td>
|
||||
<td>None</td>
|
||||
<td>Role for the <a href="https://github.com/kubernetes/kube-aggregator">kube-aggregator</a> component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:kube-dns</b></td>
|
||||
<td><b>kube-dns</b> service account in the <b>kube-system</b> namespace</td>
|
||||
<td>Role for the <a href="/docs/concepts/services-networking/dns-pod-service/">kube-dns</a> component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:node-bootstrapper</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows access to the resources required to perform <a href="/docs/admin/kubelet-tls-bootstrapping/">Kubelet TLS bootstrapping</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:node-problem-detector</b></td>
|
||||
<td>None</td>
|
||||
<td>Role for the <a href="https://github.com/kubernetes/node-problem-detector">node-problem-detector</a> component.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>system:persistent-volume-provisioner</b></td>
|
||||
<td>None</td>
|
||||
<td>Allows access to the resources required by most <a href="/docs/concepts/storage/persistent-volumes/#provisioner">dynamic volume provisioners</a>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Controller Roles
|
||||
|
||||
The [Kubernetes controller manager](/docs/admin/kube-controller-manager/) runs core control loops.
|
||||
When invoked with `--use-service-account-credentials`, each control loop is started using a separate service account.
|
||||
Corresponding roles exist for each control loop, prefixed with `system:controller:`.
|
||||
If the controller manager is not started with `--use-service-account-credentials`,
|
||||
it runs all control loops using its own credential, which must be granted all the relevant roles.
|
||||
These roles include:
|
||||
|
||||
* system:controller:attachdetach-controller
|
||||
* system:controller:certificate-controller
|
||||
* system:controller:cronjob-controller
|
||||
* system:controller:daemon-set-controller
|
||||
* system:controller:deployment-controller
|
||||
* system:controller:disruption-controller
|
||||
* system:controller:endpoint-controller
|
||||
* system:controller:generic-garbage-collector
|
||||
* system:controller:horizontal-pod-autoscaler
|
||||
* system:controller:job-controller
|
||||
* system:controller:namespace-controller
|
||||
* system:controller:node-controller
|
||||
* system:controller:persistent-volume-binder
|
||||
* system:controller:pod-garbage-collector
|
||||
* system:controller:pv-protection-controller
|
||||
* system:controller:pvc-protection-controller
|
||||
* system:controller:replicaset-controller
|
||||
* system:controller:replication-controller
|
||||
* system:controller:resourcequota-controller
|
||||
* system:controller:route-controller
|
||||
* system:controller:service-account-controller
|
||||
* system:controller:service-controller
|
||||
* system:controller:statefulset-controller
|
||||
* system:controller:ttl-controller
|
||||
|
||||
## Privilege Escalation Prevention and Bootstrapping
|
||||
|
||||
The RBAC API prevents users from escalating privileges by editing roles or role bindings.
|
||||
Because this is enforced at the API level, it applies even when the RBAC authorizer is not in use.
|
||||
|
||||
A user can only create/update a role if they already have all the permissions contained in the role,
|
||||
at the same scope as the role (cluster-wide for a `ClusterRole`, within the same namespace or cluster-wide for a `Role`).
|
||||
For example, if "user-1" does not have the ability to list secrets cluster-wide, they cannot create a `ClusterRole`
|
||||
containing that permission. To allow a user to create/update roles:
|
||||
|
||||
1. Grant them a role that allows them to create/update `Role` or `ClusterRole` objects, as desired.
|
||||
2. Grant them roles containing the permissions you would want them to be able to set in a `Role` or `ClusterRole`. If they attempt to create or modify a `Role` or `ClusterRole` with permissions they themselves have not been granted, the API request will be forbidden.
|
||||
|
||||
A user can only create/update a role binding if they already have all the permissions contained in the referenced role
|
||||
(at the same scope as the role binding) *or* if they've been given explicit permission to perform the `bind` verb on the referenced role.
|
||||
For example, if "user-1" does not have the ability to list secrets cluster-wide, they cannot create a `ClusterRoleBinding`
|
||||
to a role that grants that permission. To allow a user to create/update role bindings:
|
||||
|
||||
1. Grant them a role that allows them to create/update `RoleBinding` or `ClusterRoleBinding` objects, as desired.
|
||||
2. Grant them permissions needed to bind a particular role:
|
||||
* implicitly, by giving them the permissions contained in the role.
|
||||
* explicitly, by giving them permission to perform the `bind` verb on the particular role (or cluster role).
|
||||
|
||||
For example, this cluster role and role binding would allow "user-1" to grant other users the `admin`, `edit`, and `view` roles in the "user-1-namespace" namespace:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: role-grantor
|
||||
rules:
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["rolebindings"]
|
||||
verbs: ["create"]
|
||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||
resources: ["clusterroles"]
|
||||
verbs: ["bind"]
|
||||
resourceNames: ["admin","edit","view"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: role-grantor-binding
|
||||
namespace: user-1-namespace
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: role-grantor
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: User
|
||||
name: user-1
|
||||
```
|
||||
|
||||
When bootstrapping the first roles and role bindings, it is necessary for the initial user to grant permissions they do not yet have.
|
||||
To bootstrap initial roles and role bindings:
|
||||
|
||||
* Use a credential with the `system:masters` group, which is bound to the `cluster-admin` super-user role by the default bindings.
|
||||
* If your API server runs with the insecure port enabled (`--insecure-port`), you can also make API calls via that port, which does not enforce authentication or authorization.
|
||||
|
||||
## Command-line Utilities
|
||||
|
||||
Two `kubectl` commands exist to grant roles within a namespace or across the entire cluster.
|
||||
|
||||
### `kubectl create rolebinding`
|
||||
|
||||
Grants a `Role` or `ClusterRole` within a specific namespace. Examples:
|
||||
|
||||
* Grant the `admin` `ClusterRole` to a user named "bob" in the namespace "acme":
|
||||
|
||||
`kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme`
|
||||
|
||||
* Grant the `view` `ClusterRole` to a service account named "myapp" in the namespace "acme":
|
||||
|
||||
`kubectl create rolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme`
|
||||
|
||||
### `kubectl create clusterrolebinding`
|
||||
|
||||
Grants a `ClusterRole` across the entire cluster, including all namespaces. Examples:
|
||||
|
||||
* Grant the `cluster-admin` `ClusterRole` to a user named "root" across the entire cluster:
|
||||
|
||||
`kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root`
|
||||
|
||||
* Grant the `system:node` `ClusterRole` to a user named "kubelet" across the entire cluster:
|
||||
|
||||
`kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet`
|
||||
|
||||
* Grant the `view` `ClusterRole` to a service account named "myapp" in the namespace "acme" across the entire cluster:
|
||||
|
||||
`kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp`
|
||||
|
||||
See the CLI help for detailed usage.
|
||||
|
||||
## Service Account Permissions
|
||||
|
||||
Default RBAC policies grant scoped permissions to control-plane components, nodes,
|
||||
and controllers, but grant *no permissions* to service accounts outside the "kube-system" namespace
|
||||
(beyond discovery permissions given to all authenticated users).
|
||||
|
||||
This allows you to grant particular roles to particular service accounts as needed.
|
||||
Fine-grained role bindings provide greater security, but require more effort to administrate.
|
||||
Broader grants can give unnecessary (and potentially escalating) API access to service accounts, but are easier to administrate.
|
||||
|
||||
In order from most secure to least secure, the approaches are:
|
||||
|
||||
1. Grant a role to an application-specific service account (best practice)
|
||||
|
||||
This requires the application to specify a `serviceAccountName` in its pod spec,
|
||||
and for the service account to be created (via the API, application manifest, `kubectl create serviceaccount`, etc.).
|
||||
|
||||
For example, grant read-only permission within "my-namespace" to the "my-sa" service account:
|
||||
|
||||
```shell
|
||||
kubectl create rolebinding my-sa-view \
|
||||
--clusterrole=view \
|
||||
--serviceaccount=my-namespace:my-sa \
|
||||
--namespace=my-namespace
|
||||
```
|
||||
|
||||
2. Grant a role to the "default" service account in a namespace
|
||||
|
||||
If an application does not specify a `serviceAccountName`, it uses the "default" service account.
|
||||
|
||||
**NOTE:** Permissions given to the "default" service account are available to any pod in the namespace that does not specify a `serviceAccountName`.
|
||||
|
||||
For example, grant read-only permission within "my-namespace" to the "default" service account:
|
||||
|
||||
```shell
|
||||
kubectl create rolebinding default-view \
|
||||
--clusterrole=view \
|
||||
--serviceaccount=my-namespace:default \
|
||||
--namespace=my-namespace
|
||||
```
|
||||
|
||||
Many [add-ons](/docs/concepts/cluster-administration/addons/) currently run as the "default" service account in the "kube-system" namespace.
|
||||
To allow those add-ons to run with super-user access, grant cluster-admin permissions to the "default" service account in the "kube-system" namespace.
|
||||
|
||||
**NOTE:** Enabling this means the "kube-system" namespace contains secrets that grant super-user access to the API.
|
||||
|
||||
```shell
|
||||
kubectl create clusterrolebinding add-on-cluster-admin \
|
||||
--clusterrole=cluster-admin \
|
||||
--serviceaccount=kube-system:default
|
||||
```
|
||||
|
||||
3. Grant a role to all service accounts in a namespace
|
||||
|
||||
If you want all applications in a namespace to have a role, no matter what service account they use,
|
||||
you can grant a role to the service account group for that namespace.
|
||||
|
||||
For example, grant read-only permission within "my-namespace" to all service accounts in that namespace:
|
||||
|
||||
```shell
|
||||
kubectl create rolebinding serviceaccounts-view \
|
||||
--clusterrole=view \
|
||||
--group=system:serviceaccounts:my-namespace \
|
||||
--namespace=my-namespace
|
||||
```
|
||||
|
||||
4. Grant a limited role to all service accounts cluster-wide (discouraged)
|
||||
|
||||
If you don't want to manage permissions per-namespace, you can grant a cluster-wide role to all service accounts.
|
||||
|
||||
For example, grant read-only permission across all namespaces to all service accounts in the cluster:
|
||||
|
||||
```shell
|
||||
kubectl create clusterrolebinding serviceaccounts-view \
|
||||
--clusterrole=view \
|
||||
--group=system:serviceaccounts
|
||||
```
|
||||
|
||||
5. Grant super-user access to all service accounts cluster-wide (strongly discouraged)
|
||||
|
||||
If you don't care about partitioning permissions at all, you can grant super-user access to all service accounts.
|
||||
|
||||
**WARNING:** This allows any user with read access to secrets or the ability to create a pod to access super-user credentials.
|
||||
|
||||
```shell
|
||||
kubectl create clusterrolebinding serviceaccounts-cluster-admin \
|
||||
--clusterrole=cluster-admin \
|
||||
--group=system:serviceaccounts
|
||||
```
|
||||
|
||||
## Upgrading from 1.5
|
||||
|
||||
Prior to Kubernetes 1.6, many deployments used very permissive ABAC policies,
|
||||
including granting full API access to all service accounts.
|
||||
|
||||
Default RBAC policies grant scoped permissions to control-plane components, nodes,
|
||||
and controllers, but grant *no permissions* to service accounts outside the "kube-system" namespace
|
||||
(beyond discovery permissions given to all authenticated users).
|
||||
|
||||
While far more secure, this can be disruptive to existing workloads expecting to automatically receive API permissions.
|
||||
Here are two approaches for managing this transition:
|
||||
|
||||
### Parallel Authorizers
|
||||
|
||||
Run both the RBAC and ABAC authorizers, and specify a policy file that contains
|
||||
[the legacy ABAC policy](/docs/admin/authorization/abac#policy-file-format):
|
||||
|
||||
```
|
||||
--authorization-mode=RBAC,ABAC --authorization-policy-file=mypolicy.json
|
||||
```
|
||||
|
||||
The RBAC authorizer will attempt to authorize requests first. If it denies an API request,
|
||||
the ABAC authorizer is then run. This means that any request allowed by *either* the RBAC
|
||||
or ABAC policies is allowed.
|
||||
|
||||
When run with a log level of 2 or higher (`--v=2`), you can see RBAC denials in the apiserver log (prefixed with `RBAC DENY:`).
|
||||
You can use that information to determine which roles need to be granted to which users, groups, or service accounts.
|
||||
Once you have [granted roles to service accounts](#service-account-permissions) and workloads are running with no RBAC denial messages
|
||||
in the server logs, you can remove the ABAC authorizer.
|
||||
|
||||
## Permissive RBAC Permissions
|
||||
|
||||
You can replicate a permissive policy using RBAC role bindings.
|
||||
|
||||
{{< warning >}}
|
||||
**WARNING:** The following policy allows **ALL** service accounts to act as cluster administrators.
|
||||
Any application running in a container receives service account credentials automatically,
|
||||
and could perform any action against the API, including viewing secrets and modifying permissions.
|
||||
This is not a recommended policy.
|
||||
{{< /warning >}}
|
||||
|
||||
```
|
||||
kubectl create clusterrolebinding permissive-binding \
|
||||
--clusterrole=cluster-admin \
|
||||
--user=admin \
|
||||
--user=kubelet \
|
||||
--group=system:serviceaccounts
|
||||
```
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
reviewers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Webhook Mode
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
When specified, mode `Webhook` causes Kubernetes to query an outside REST
|
||||
service when determining user privileges.
|
||||
|
||||
## Configuration File Format
|
||||
|
||||
Mode `Webhook` requires a file for HTTP configuration, specify by the
|
||||
`--authorization-webhook-config-file=SOME_FILENAME` flag.
|
||||
|
||||
The configuration file uses the [kubeconfig](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)
|
||||
file format. Within the file "users" refers to the API Server webhook and
|
||||
"clusters" refers to the remote service.
|
||||
|
||||
A configuration example which uses HTTPS client auth:
|
||||
|
||||
```yaml
|
||||
# clusters refers to the remote service.
|
||||
clusters:
|
||||
- name: name-of-remote-authz-service
|
||||
cluster:
|
||||
# CA for verifying the remote service.
|
||||
certificate-authority: /path/to/ca.pem
|
||||
# URL of remote service to query. Must use 'https'. May not include parameters.
|
||||
server: https://authz.example.com/authorize
|
||||
|
||||
# users refers to the API Server's webhook configuration.
|
||||
users:
|
||||
- name: name-of-api-server
|
||||
user:
|
||||
client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
|
||||
client-key: /path/to/key.pem # key matching the cert
|
||||
|
||||
# kubeconfig files require a context. Provide one for the API Server.
|
||||
current-context: webhook
|
||||
contexts:
|
||||
- context:
|
||||
cluster: name-of-remote-authz-service
|
||||
user: name-of-api-server
|
||||
name: webhook
|
||||
```
|
||||
|
||||
## Request Payloads
|
||||
|
||||
When faced with an authorization decision, the API Server POSTs a JSON-
|
||||
serialized `authorization.k8s.io/v1beta1` `SubjectAccessReview` object describing the
|
||||
action. This object contains fields describing the user attempting to make the
|
||||
request, and either details about the resource being accessed or requests
|
||||
attributes.
|
||||
|
||||
Note that webhook API objects are subject to the same [versioning compatibility rules](/docs/concepts/overview/kubernetes-api/)
|
||||
as other Kubernetes API objects. Implementers should be aware of looser
|
||||
compatibility promises for beta objects and check the "apiVersion" field of the
|
||||
request to ensure correct deserialization. Additionally, the API Server must
|
||||
enable the `authorization.k8s.io/v1beta1` API extensions group (`--runtime-config=authorization.k8s.io/v1beta1=true`).
|
||||
|
||||
An example request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"resourceAttributes": {
|
||||
"namespace": "kittensandponies",
|
||||
"verb": "get",
|
||||
"group": "unicorn.example.org",
|
||||
"resource": "pods"
|
||||
},
|
||||
"user": "jane",
|
||||
"group": [
|
||||
"group1",
|
||||
"group2"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The remote service is expected to fill the `status` field of
|
||||
the request and respond to either allow or disallow access. The response body's
|
||||
`spec` field is ignored and may be omitted. A permissive response would return:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"status": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To disallow access, the remote service would return:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"status": {
|
||||
"allowed": false,
|
||||
"reason": "user does not have read access to the namespace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Access to non-resource paths are sent as:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"nonResourceAttributes": {
|
||||
"path": "/debug",
|
||||
"verb": "get"
|
||||
},
|
||||
"user": "jane",
|
||||
"group": [
|
||||
"group1",
|
||||
"group2"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Non-resource paths include: `/api`, `/apis`, `/metrics`, `/resetMetrics`,
|
||||
`/logs`, `/debug`, `/healthz`, `/swagger-ui/`, `/swaggerapi/`, `/ui`, and
|
||||
`/version.` Clients require access to `/api`, `/api/*`, `/apis`, `/apis/*`,
|
||||
and `/version` to discover what resources and versions are present on the server.
|
||||
Access to other non-resource paths can be disallowed without restricting access
|
||||
to the REST api.
|
||||
|
||||
For further documentation refer to the authorization.v1beta1 API objects and
|
||||
[webhook.go](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
reviewers:
|
||||
- jbeda
|
||||
title: Authenticating with Bootstrap Tokens
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
Bootstrap tokens are a simple bearer token that is meant to be used when
|
||||
creating new clusters or joining new nodes to an existing cluster. It was built
|
||||
to support [`kubeadm`](/docs/admin/kubeadm/), but can be used in other contexts
|
||||
for users that wish to start clusters without `kubeadm`. It is also built to
|
||||
work, via RBAC policy, with the [Kubelet TLS
|
||||
Bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) system.
|
||||
|
||||
Bootstrap Tokens are defined with a specific type
|
||||
(`bootstrap.kubernetes.io/token`) of secrets that lives in the `kube-system`
|
||||
namespace. These Secrets are then read by the Bootstrap Authenticator in the
|
||||
API Server. Expired tokens are removed with the TokenCleaner controller in the
|
||||
Controller Manager. The tokens are also used to create a signature for a
|
||||
specific ConfigMap used in a "discovery" process through a BootstrapSigner
|
||||
controller.
|
||||
|
||||
{{< feature-state state="beta" >}}
|
||||
|
||||
## Token Format
|
||||
|
||||
Bootstrap Tokens take the form of `abcdef.0123456789abcdef`. More formally,
|
||||
they must match the regular expression `[a-z0-9]{6}\.[a-z0-9]{16}`.
|
||||
|
||||
The first part of the token is the "Token ID" and is considered public
|
||||
information. It is used when referring to a token without leaking the secret
|
||||
part used for authentication. The second part is the "Token Secret" and should
|
||||
only be shared with trusted parties.
|
||||
|
||||
## Enabling Bootstrap Token Authentication
|
||||
|
||||
The Bootstrap Token authenticator can be enabled using the following flag on the
|
||||
API server:
|
||||
|
||||
```
|
||||
--enable-bootstrap-token-auth
|
||||
```
|
||||
|
||||
When enabled, bootstrapping tokens can be used as bearer token credentials to
|
||||
authenticate requests against the API server.
|
||||
|
||||
```http
|
||||
Authorization: Bearer 07401b.f395accd246ae52d
|
||||
```
|
||||
|
||||
Tokens authenticate as the username `system:bootstrap:<token id>` and are members
|
||||
of the group `system:bootstrappers`. Additional groups may be specified in the
|
||||
token's Secret.
|
||||
|
||||
Expired tokens can be deleted automatically by enabling the `tokencleaner`
|
||||
controller on the controller manager.
|
||||
|
||||
```
|
||||
--controllers=*,tokencleaner
|
||||
```
|
||||
|
||||
## Bootstrap Token Secret Format
|
||||
|
||||
Each valid token is backed by a secret in the `kube-system` namespace. You can
|
||||
find the full design doc
|
||||
[here](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/cluster-lifecycle/bootstrap-discovery.md).
|
||||
|
||||
Here is what the secret looks like.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
# Name MUST be of form "bootstrap-token-<token id>"
|
||||
name: bootstrap-token-07401b
|
||||
namespace: kube-system
|
||||
|
||||
# Type MUST be 'bootstrap.kubernetes.io/token'
|
||||
type: bootstrap.kubernetes.io/token
|
||||
stringData:
|
||||
# Human readable description. Optional.
|
||||
description: "The default bootstrap token generated by 'kubeadm init'."
|
||||
|
||||
# Token ID and secret. Required.
|
||||
token-id: 07401b
|
||||
token-secret: f395accd246ae52d
|
||||
|
||||
# Expiration. Optional.
|
||||
expiration: 2017-03-10T03:22:11Z
|
||||
|
||||
# Allowed usages.
|
||||
usage-bootstrap-authentication: "true"
|
||||
usage-bootstrap-signing: "true"
|
||||
|
||||
# Extra groups to authenticate the token as. Must start with "system:bootstrappers:"
|
||||
auth-extra-groups: system:bootstrappers:worker,system:bootstrappers:ingress
|
||||
```
|
||||
|
||||
The type of the secret must be `bootstrap.kubernetes.io/token` and the name must
|
||||
be `bootstrap-token-<token id>`. It must also exist in the `kube-system`
|
||||
namespace.
|
||||
|
||||
The `usage-bootstrap-*` members indicate what this secret is intended to be used
|
||||
for. A value must be set to `true` to be enabled.
|
||||
|
||||
* `usage-bootstrap-authentication` indicates that the token can be used to
|
||||
authenticate to the API server as a bearer token.
|
||||
* `usage-bootstrap-signing` indicates that the token may be used to sign the
|
||||
`cluster-info` ConfigMap as described below.
|
||||
|
||||
The `expiration` field controls the expiry of the token. Expired tokens are
|
||||
rejected when used for authentication and ignored during ConfigMap signing.
|
||||
The expiry value is encoded as an absolute UTC time using RFC3339. Enable the
|
||||
`tokencleaner` controller to automatically delete expired tokens.
|
||||
|
||||
## Token Management with `kubeadm`
|
||||
|
||||
You can use the `kubeadm` tool to manage tokens on a running cluster. See the
|
||||
[`kubeadm token` docs](/docs/admin/kubeadm/#manage-tokens) for details.
|
||||
|
||||
## ConfigMap Signing
|
||||
|
||||
In addition to authentication, the tokens can be used to sign a ConfigMap. This
|
||||
is used early in a cluster bootstrap process before the client trusts the API
|
||||
server. The signed ConfigMap can be authenticated by the shared token.
|
||||
|
||||
Enable ConfigMap signing by enabling the `bootstrapsigner` controller on the
|
||||
Controller Manager.
|
||||
|
||||
```
|
||||
--controllers=*,bootstrapsigner
|
||||
```
|
||||
|
||||
The ConfigMap that is signed is `cluster-info` in the `kube-public` namespace.
|
||||
The typical flow is that a client reads this ConfigMap while unauthenticated and
|
||||
ignoring TLS errors. It then validates the payload of the ConfigMap by looking
|
||||
at a signature embedded in the ConfigMap.
|
||||
|
||||
The ConfigMap may look like this:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cluster-info
|
||||
namespace: kube-public
|
||||
data:
|
||||
jws-kubeconfig-07401b: eyJhbGciOiJIUzI1NiIsImtpZCI6IjA3NDAxYiJ9..tYEfbo6zDNo40MQE07aZcQX2m3EB2rO3NuXtxVMYm9U
|
||||
kubeconfig: |
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: <really long certificate data>
|
||||
server: https://10.138.0.2:6443
|
||||
name: ""
|
||||
contexts: []
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users: []
|
||||
```
|
||||
|
||||
The `kubeconfig` member of the ConfigMap is a config file with just the cluster
|
||||
information filled out. The key thing being communicated here is the
|
||||
`certificate-authority-data`. This may be expanded in the future.
|
||||
|
||||
The signature is a JWS signature using the "detached" mode. To validate the
|
||||
signature, the user should encode the `kubeconfig` payload according to JWS
|
||||
rules (base64 encoded while discarding any trailing `=`). That encoded payload
|
||||
is then used to form a whole JWS by inserting it between the 2 dots. You can
|
||||
verify the JWS using the `HS256` scheme (HMAC-SHA256) with the full token (e.g.
|
||||
`07401b.f395accd246ae52d`) as the shared secret. Users _must_ verify that HS256
|
||||
is used.
|
||||
|
||||
WARNING: Any party with a bootstrapping token can create a valid signature for that
|
||||
token. When using ConfigMap signing it's discouraged to share the same token with
|
||||
many clients, since a compromised client can potentially man-in-the middle another
|
||||
client relying on the signature to bootstrap TLS trust.
|
||||
|
||||
Consult the [kubeadm security model](/docs/reference/generated/kubeadm/#security-model)
|
||||
section for more information.
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
title: Building Large Clusters
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
At {{< param "version" >}}, Kubernetes supports clusters with up to 5000 nodes. More specifically, we support configurations that meet *all* of the following criteria:
|
||||
|
||||
* No more than 5000 nodes
|
||||
* No more than 150000 total pods
|
||||
* No more than 300000 total containers
|
||||
* No more than 100 pods per node
|
||||
|
||||
<br>
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Setup
|
||||
|
||||
A cluster is a set of nodes (physical or virtual machines) running Kubernetes agents, managed by a "master" (the cluster-level control plane).
|
||||
|
||||
Normally the number of nodes in a cluster is controlled by the value `NUM_NODES` in the platform-specific `config-default.sh` file (for example, see [GCE's `config-default.sh`](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/gce/config-default.sh)).
|
||||
|
||||
Simply changing that value to something very large, however, may cause the setup script to fail for many cloud providers. A GCE deployment, for example, will run in to quota issues and fail to bring the cluster up.
|
||||
|
||||
When setting up a large Kubernetes cluster, the following issues must be considered.
|
||||
|
||||
### Quota Issues
|
||||
|
||||
To avoid running into cloud provider quota issues, when creating a cluster with many nodes, consider:
|
||||
|
||||
* Increase the quota for things like CPU, IPs, etc.
|
||||
* In [GCE, for example,](https://cloud.google.com/compute/docs/resource-quotas) you'll want to increase the quota for:
|
||||
* CPUs
|
||||
* VM instances
|
||||
* Total persistent disk reserved
|
||||
* In-use IP addresses
|
||||
* Firewall Rules
|
||||
* Forwarding rules
|
||||
* Routes
|
||||
* Target pools
|
||||
* Gating the setup script so that it brings up new node VMs in smaller batches with waits in between, because some cloud providers rate limit the creation of VMs.
|
||||
|
||||
### Etcd storage
|
||||
|
||||
To improve performance of large clusters, we store events in a separate dedicated etcd instance.
|
||||
|
||||
When creating a cluster, existing salt scripts:
|
||||
|
||||
* start and configure additional etcd instance
|
||||
* configure api-server to use it for storing events
|
||||
|
||||
### Size of master and master components
|
||||
|
||||
On GCE/Google Kubernetes Engine, and AWS, `kube-up` automatically configures the proper VM size for your master depending on the number of nodes
|
||||
in your cluster. On other providers, you will need to configure it manually. For reference, the sizes we use on GCE are
|
||||
|
||||
* 1-5 nodes: n1-standard-1
|
||||
* 6-10 nodes: n1-standard-2
|
||||
* 11-100 nodes: n1-standard-4
|
||||
* 101-250 nodes: n1-standard-8
|
||||
* 251-500 nodes: n1-standard-16
|
||||
* more than 500 nodes: n1-standard-32
|
||||
|
||||
And the sizes we use on AWS are
|
||||
|
||||
* 1-5 nodes: m3.medium
|
||||
* 6-10 nodes: m3.large
|
||||
* 11-100 nodes: m3.xlarge
|
||||
* 101-250 nodes: m3.2xlarge
|
||||
* 251-500 nodes: c4.4xlarge
|
||||
* more than 500 nodes: c4.8xlarge
|
||||
|
||||
Note that these master node sizes are currently only set at cluster startup time, and are not adjusted if you later scale your cluster up or down (e.g. manually removing or adding nodes, or using a cluster autoscaler).
|
||||
|
||||
### Addon Resources
|
||||
|
||||
To prevent memory leaks or other resource issues in [cluster addons](https://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons) from consuming all the resources available on a node, Kubernetes sets resource limits on addon containers to limit the CPU and Memory resources they can consume (See PR [#10653](http://pr.k8s.io/10653/files) and [#10778](http://pr.k8s.io/10778/files)).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: fluentd-cloud-logging
|
||||
image: k8s.gcr.io/fluentd-gcp:1.16
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
```
|
||||
|
||||
Except for Heapster, these limits are static and are based on data we collected from addons running on 4-node clusters (see [#10335](http://issue.k8s.io/10335#issuecomment-117861225)). The addons consume a lot more resources when running on large deployment clusters (see [#5880](http://issue.k8s.io/5880#issuecomment-113984085)). So, if a large cluster is deployed without adjusting these values, the addons may continuously get killed because they keep hitting the limits.
|
||||
|
||||
To avoid running into cluster addon resource issues, when creating a cluster with many nodes, consider the following:
|
||||
|
||||
* Scale memory and CPU limits for each of the following addons, if used, as you scale up the size of cluster (there is one replica of each handling the entire cluster so memory and CPU usage tends to grow proportionally with size/load on cluster):
|
||||
* [InfluxDB and Grafana](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/cluster-monitoring/influxdb/influxdb-grafana-controller.yaml)
|
||||
* [kubedns, dnsmasq, and sidecar](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/kube-dns.yaml.in)
|
||||
* [Kibana](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/kibana-deployment.yaml)
|
||||
* Scale number of replicas for the following addons, if used, along with the size of cluster (there are multiple replicas of each so increasing replicas should help handle increased load, but, since load per replica also increases slightly, also consider increasing CPU/memory limits):
|
||||
* [elasticsearch](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/es-statefulset.yaml)
|
||||
* Increase memory and CPU limits slightly for each of the following addons, if used, along with the size of cluster (there is one replica per node but CPU/memory usage increases slightly along with cluster load/size as well):
|
||||
* [FluentD with ElasticSearch Plugin](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/fluentd-es-ds.yaml)
|
||||
* [FluentD with GCP Plugin](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml)
|
||||
|
||||
Heapster's resource limits are set dynamically based on the initial size of your cluster (see [#16185](http://issue.k8s.io/16185)
|
||||
and [#22940](http://issue.k8s.io/22940)). If you find that Heapster is running
|
||||
out of resources, you should adjust the formulas that compute heapster memory request (see those PRs for details).
|
||||
|
||||
For directions on how to detect if addon containers are hitting resource limits, see the [Troubleshooting section of Compute Resources](/docs/concepts/configuration/manage-compute-resources-container/#troubleshooting).
|
||||
|
||||
In the [future](http://issue.k8s.io/13048), we anticipate to set all cluster addon resource limits based on cluster size, and to dynamically adjust them if you grow or shrink your cluster.
|
||||
We welcome PRs that implement those features.
|
||||
|
||||
### Allowing minor node failure at startup
|
||||
|
||||
For various reasons (see [#18969](https://github.com/kubernetes/kubernetes/issues/18969) for more details) running
|
||||
`kube-up.sh` with a very large `NUM_NODES` may fail due to a very small number of nodes not coming up properly.
|
||||
Currently you have two choices: restart the cluster (`kube-down.sh` and then `kube-up.sh` again), or before
|
||||
running `kube-up.sh` set the environment variable `ALLOWED_NOTREADY_NODES` to whatever value you feel comfortable
|
||||
with. This will allow `kube-up.sh` to succeed with fewer than `NUM_NODES` coming up. Depending on the
|
||||
reason for the failure, those additional nodes may join later or the cluster may remain at a size of
|
||||
`NUM_NODES - ALLOWED_NOTREADY_NODES`.
|
||||
@@ -0,0 +1,305 @@
|
||||
---
|
||||
reviewers:
|
||||
- smarterclayton
|
||||
- lavalamp
|
||||
- whitlockjc
|
||||
- caesarxuchao
|
||||
- deads2k
|
||||
title: Dynamic Admission Control
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
The [admission controllers documentation](/docs/admin/admission-controllers/)
|
||||
introduces how to use standard, plugin-style admission controllers. However,
|
||||
plugin admission controllers are not flexible enough for all use cases, due to
|
||||
the following:
|
||||
|
||||
* They need to be compiled into kube-apiserver.
|
||||
* They are only configurable when the apiserver starts up.
|
||||
|
||||
Two features, *Admission Webhooks* (beta in 1.9) and *Initializers* (alpha),
|
||||
address these limitations. They allow admission controllers to be developed
|
||||
out-of-tree and configured at runtime.
|
||||
|
||||
This page describes how to use Admission Webhooks and Initializers.
|
||||
|
||||
## Admission Webhooks
|
||||
|
||||
### What are admission webhooks?
|
||||
|
||||
Admission webhooks are HTTP callbacks that receive admission requests and do
|
||||
something with them. You can define two types of admission webhooks,
|
||||
[validating admission Webhook](/docs/admin/admission-controllers.md#validatingadmissionwebhook-alpha-in-18-beta-in-19)
|
||||
and
|
||||
[mutating admission webhook](/docs/admin/admission-controllers.md#mutatingadmissionwebhook-beta-in-19).
|
||||
With validating admission Webhooks, you may reject requests to enforce custom
|
||||
admission policies. With mutating admission Webhooks, you may change requests to
|
||||
enforce custom defaults.
|
||||
|
||||
### Experimenting with admission webhooks
|
||||
|
||||
Admission webhooks are essentially part of the cluster control-plane. You should
|
||||
write and deploy them with great caution. Please read the [user
|
||||
guides](https://github.com/kubernetes/website/pull/6836/files)(WIP) for
|
||||
instructions if you intend to write/deploy production-grade admission webhooks.
|
||||
In the following, we describe how to quickly experiment with admission webhooks.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* Ensure that the Kubernetes cluster is at least as new as v1.9.
|
||||
|
||||
* Ensure that MutatingAdmissionWebhook and ValidatingAdmissionWebhook
|
||||
admission controllers are enabled.
|
||||
[Here](/docs/admin/admission-controllers.md#is-there-a-recommended-set-of-admission-controllers-to-use)
|
||||
is a recommended set of admission controllers to enable in general.
|
||||
|
||||
* Ensure that the admissionregistration.k8s.io/v1beta1 API is enabled.
|
||||
|
||||
### Write an admission webhook server
|
||||
|
||||
Please refer to the implementation of the [admission webhook
|
||||
server](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/main.go)
|
||||
that is validated in a Kubernetes e2e test. The webhook handles the
|
||||
`admissionReview` requests sent by the apiservers, and sends back its decision
|
||||
wrapped in `admissionResponse`.
|
||||
|
||||
The example admission webhook server leaves the `ClientAuth` field
|
||||
[empty](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/config.go#L48-L49),
|
||||
which defaults to `NoClientCert`. This means that the webhook server does not
|
||||
authenticate the identity of the clients, supposedly apiservers. If you need
|
||||
mutual TLS or other ways to authenticate the clients, see
|
||||
how to [authenticate apiservers](#authenticate-apiservers).
|
||||
|
||||
### Deploy the admission webhook service
|
||||
|
||||
The webhook server in the e2e test is deployed in the Kubernetes cluster, via
|
||||
the [deployment API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deployment-v1beta1-apps).
|
||||
The test also creates a [service](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core)
|
||||
as the front-end of the webhook server. See
|
||||
[code](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/e2e/apimachinery/webhook.go#L196).
|
||||
|
||||
You may also deploy your webhooks outside of the cluster. You will need to update
|
||||
your [webhook client configurations](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/staging/src/k8s.io/api/admissionregistration/v1beta1/types.go#L218) accordingly.
|
||||
|
||||
### Configure admission webhooks on the fly
|
||||
|
||||
You can dynamically configure what resources are subject to what admission
|
||||
webhooks via
|
||||
[ValidatingWebhookConfiguration](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/staging/src/k8s.io/api/admissionregistration/v1beta1/types.go#L68)
|
||||
or
|
||||
[MutatingWebhookConifuration](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/staging/src/k8s.io/api/admissionregistration/v1beta1/types.go#L98).
|
||||
|
||||
The following is an example `validatingWebhookConfiguration`, a mutating webhook
|
||||
configuration is similar.
|
||||
|
||||
```yaml
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: <name of this configuration object>
|
||||
webhooks:
|
||||
- name: <webhook name, e.g., pod-policy.example.io>
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
resources:
|
||||
- pods
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: <namespace of the front-end service>
|
||||
name: <name of the front-end service>
|
||||
caBundle: <pem encoded ca cert that signs the server cert used by the webhook>
|
||||
```
|
||||
|
||||
*Note*: When using `clientConfig.service`, the server cert must be valid for
|
||||
`<svc_name>.<svc_namespace>.svc`.
|
||||
|
||||
When an apiserver receives a request that matches one of the `rules`, the
|
||||
apiserver sends an `admissionReview` request to webhook as specified in the
|
||||
`clientConfig`.
|
||||
|
||||
After you create the webhook configuration, the system will take a few seconds
|
||||
to honor the new configuration.
|
||||
|
||||
{{< note >}}
|
||||
**Note** When the webhook plugin is deployed into the Kubernetes cluster as a
|
||||
service, it has to expose its service on the 443 port. The communication
|
||||
between the API server and the webhook service may fail if a different port
|
||||
is used.
|
||||
{{< /note >}}
|
||||
|
||||
### Authenticate apiservers
|
||||
|
||||
If your admission webhooks require authentication, you can configure the
|
||||
apiservers to use basic auth, bearer token, or a cert to authenticate itself to
|
||||
the webhooks. There are three steps to complete the configuration.
|
||||
|
||||
* When starting the apiserver, specify the location of the admission control
|
||||
configuration file via the `--admission-control-config-file` flag.
|
||||
|
||||
* In the admission control configuration file, specify where the
|
||||
MutatingAdmissionWebhook controller and ValidatingAdmissionWebhook controller
|
||||
should read the credentials. The credentials are stored in kubeConfig files
|
||||
(yes, the same schema that's used by kubectl), so the field name is
|
||||
`kubeConfigFile`. Here is an example admission control configuration file:
|
||||
|
||||
```yaml
|
||||
apiVersion: apiserver.k8s.io/v1alpha1
|
||||
kind: AdmissionConfiguration
|
||||
plugins:
|
||||
- name: ValidatingAdmissionWebhook
|
||||
configuration:
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: WebhookAdmission
|
||||
kubeConfigFile: <path-to-kubeconfig-file>
|
||||
- name: MutatingAdmissionWebhook
|
||||
configuration:
|
||||
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||
kind: WebhookAdmission
|
||||
kubeConfigFile: <path-to-kubeconfig-file>
|
||||
```
|
||||
|
||||
The schema of `admissionConfiguration` is defined
|
||||
[here](https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.0/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go#L27).
|
||||
|
||||
* In the kubeConfig file, provide the credentials:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
users:
|
||||
# DNS name of webhook service, i.e., <service name>.<namespace>.svc, or the URL
|
||||
# of the webhook server.
|
||||
- name: 'webhook1.ns1.svc'
|
||||
user:
|
||||
client-certificate-data: <pem encoded certificate>
|
||||
client-key-data: <pem encoded key>
|
||||
# The `name` supports using * to wildmatch prefixing segments.
|
||||
- name: '*.webhook-company.org'
|
||||
user:
|
||||
password: <password>
|
||||
username: <name>
|
||||
# '*' is the default match.
|
||||
- name: '*'
|
||||
user:
|
||||
token: <token>
|
||||
```
|
||||
|
||||
Of course you need to set up the webhook server to handle these authentications.
|
||||
|
||||
## Initializers
|
||||
|
||||
### What are initializers?
|
||||
|
||||
*Initializer* has two meanings:
|
||||
|
||||
* A list of pending pre-initialization tasks, stored in every object's metadata
|
||||
(e.g., "AddMyCorporatePolicySidecar").
|
||||
|
||||
* A user customized controller, which actually performs those tasks. The name of the task
|
||||
corresponds to the controller which performs the task. For clarity, we call
|
||||
them *initializer controllers* in this page.
|
||||
|
||||
Once the controller has performed its assigned task, it removes its name from
|
||||
the list. For example, it may send a PATCH that inserts a container in a pod and
|
||||
also removes its name from `metadata.initializers.pending`. Initializers may make
|
||||
mutations to objects.
|
||||
|
||||
Objects which have a non-empty initializer list are considered uninitialized,
|
||||
and are not visible in the API unless specifically requested by using the query parameter,
|
||||
`?includeUninitialized=true`.
|
||||
|
||||
### When to use initializers?
|
||||
|
||||
Initializers are useful for admins to force policies (e.g., the
|
||||
[AlwaysPullImages](/docs/admin/admission-controllers/#alwayspullimages)
|
||||
admission controller), or to inject defaults (e.g., the
|
||||
[DefaultStorageClass](/docs/admin/admission-controllers/#defaultstorageclass)
|
||||
admission controller), etc.
|
||||
|
||||
**Note:** If your use case does not involve mutating objects, consider using
|
||||
external admission webhooks, as they have better performance.
|
||||
|
||||
### How are initializers triggered?
|
||||
|
||||
When an object is POSTed, it is checked against all existing
|
||||
`initializerConfiguration` objects (explained below). For all that it matches,
|
||||
all `spec.initializers[].name`s are appended to the new object's
|
||||
`metadata.initializers.pending` field.
|
||||
|
||||
An initializer controller should list and watch for uninitialized objects, by
|
||||
using the query parameter `?includeUninitialized=true`. If using client-go, just
|
||||
set
|
||||
[listOptions.includeUninitialized](https://github.com/kubernetes/kubernetes/blob/v1.7.0-rc.1/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/types.go#L315)
|
||||
to true.
|
||||
|
||||
For the observed uninitialized objects, an initializer controller should first
|
||||
check if its name matches `metadata.initializers.pending[0]`. If so, it should then
|
||||
perform its assigned task and remove its name from the list.
|
||||
|
||||
### Enable initializers alpha feature
|
||||
|
||||
*Initializers* is an alpha feature, so it is disabled by default. To turn it on,
|
||||
you need to:
|
||||
|
||||
* Include "Initializers" in the `--enable-admission-plugins` flag when starting
|
||||
`kube-apiserver`. If you have multiple `kube-apiserver` replicas, all should
|
||||
have the same flag setting.
|
||||
|
||||
* Enable the dynamic admission controller registration API by adding
|
||||
`admissionregistration.k8s.io/v1alpha1` to the `--runtime-config` flag passed
|
||||
to `kube-apiserver`, e.g.
|
||||
`--runtime-config=admissionregistration.k8s.io/v1alpha1`. Again, all replicas
|
||||
should have the same flag setting.
|
||||
|
||||
### Deploy an initializer controller
|
||||
|
||||
You should deploy an initializer controller via the [deployment
|
||||
API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deployment-v1beta1-apps).
|
||||
|
||||
### Configure initializers on the fly
|
||||
|
||||
You can configure what initializers are enabled and what resources are subject
|
||||
to the initializers by creating `initializerConfiguration` resources.
|
||||
|
||||
You should first deploy the initializer controller and make sure that it is
|
||||
working properly before creating the `initializerConfiguration`. Otherwise, any
|
||||
newly created resources will be stuck in an uninitialized state.
|
||||
|
||||
The following is an example `initializerConfiguration`:
|
||||
|
||||
```yaml
|
||||
apiVersion: admissionregistration.k8s.io/v1alpha1
|
||||
kind: InitializerConfiguration
|
||||
metadata:
|
||||
name: example-config
|
||||
initializers:
|
||||
# the name needs to be fully qualified, i.e., containing at least two "."
|
||||
- name: podimage.example.com
|
||||
rules:
|
||||
# apiGroups, apiVersion, resources all support wildcard "*".
|
||||
# "*" cannot be mixed with non-wildcard.
|
||||
- apiGroups:
|
||||
- ""
|
||||
apiVersions:
|
||||
- v1
|
||||
resources:
|
||||
- pods
|
||||
```
|
||||
|
||||
After you create the `initializerConfiguration`, the system will take a few
|
||||
seconds to honor the new configuration. Then, `"podimage.example.com"` will be
|
||||
appended to the `metadata.initializers.pending` field of newly created pods. You
|
||||
should already have a ready "podimage" initializer controller that handles pods
|
||||
whose `metadata.initializers.pending[0].name="podimage.example.com"`. Otherwise
|
||||
the pods will be stuck in an uninitialized state.
|
||||
|
||||
Make sure that all expansions of the `<apiGroup, apiVersions, resources>` tuple
|
||||
in a `rule` are valid. If they are not, separate them in different `rules`.
|
||||
@@ -0,0 +1,5 @@
|
||||
reviewers:
|
||||
- madhusudancs
|
||||
- mml
|
||||
- nikhiljindal
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
---
|
||||
reviewers:
|
||||
- madhusudancs
|
||||
- mml
|
||||
- nikhiljindal
|
||||
title: (Deprecated) Using `federation-up` and `deploy.sh`
|
||||
toc_hide: true
|
||||
---
|
||||
|
||||
## The mechanisms explained in this doc to setup federation are deprecated. [`kubefed`](/docs/tasks/federation/set-up-cluster-federation-kubefed/) is now the recommended way to deploy federation.
|
||||
|
||||
This guide explains how to set up cluster federation that lets us control multiple Kubernetes clusters.
|
||||
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This guide assumes that you have a running Kubernetes cluster.
|
||||
If you need to start a new cluster, see the [getting started guides](/docs/setup/) for instructions on bringing a cluster up.
|
||||
|
||||
To use the commands in this guide, you must download a Kubernetes release from the
|
||||
[getting started binary releases](/docs/getting-started-guides/binary_release/) and
|
||||
extract into a directory; all the commands in this guide are run from
|
||||
that directory.
|
||||
|
||||
```shell
|
||||
$ curl -L https://github.com/kubernetes/kubernetes/releases/download/v1.4.0/kubernetes.tar.gz | tar xvzf -
|
||||
$ cd kubernetes
|
||||
```
|
||||
|
||||
You must also have a Docker installation running
|
||||
locally--meaning on the machine where you run the commands described in this
|
||||
guide.
|
||||
|
||||
## Setting up a federation control plane
|
||||
|
||||
Setting up federation requires running the federation control plane which
|
||||
consists of etcd, federation-apiserver (via the hyperkube binary) and
|
||||
federation-controller-manager (also via the hyperkube binary). You can run
|
||||
these binaries as pods on an existing Kubernetes cluster.
|
||||
|
||||
Note: This is a new mechanism to turn up Kubernetes Cluster Federation. If
|
||||
you want to follow the old mechanism, please refer to the section
|
||||
[Previous Federation turn up mechanism](#previous-federation-turn-up-mechanism)
|
||||
at the end of this guide.
|
||||
|
||||
### Initial setup
|
||||
|
||||
Create a directory to store the configs required to turn up federation
|
||||
and export that directory path in the environment variable
|
||||
`FEDERATION_OUTPUT_ROOT`. This can be an existing directory, but it is
|
||||
highly recommended to create a separate directory so that it is easier
|
||||
to clean up later.
|
||||
|
||||
```shell
|
||||
$ export FEDERATION_OUTPUT_ROOT="${PWD}/_output/federation"
|
||||
$ mkdir -p "${FEDERATION_OUTPUT_ROOT}"
|
||||
```
|
||||
|
||||
Initialize the setup.
|
||||
|
||||
```shell
|
||||
$ federation/deploy/deploy.sh init
|
||||
```
|
||||
|
||||
Optionally, you can create/edit `${FEDERATION_OUTPUT_ROOT}/values.yaml` to
|
||||
customize any value in
|
||||
[federation/federation/manifests/federation/values.yaml](https://github.com/madhusudancs/kubernetes-anywhere/blob/federation/federation/manifests/federation/values.yaml). Example:
|
||||
|
||||
```yaml
|
||||
apiserverRegistry: "gcr.io/myrepository"
|
||||
apiserverVersion: "v1.5.0-alpha.0.1010+892a6d7af59c0b"
|
||||
controllerManagerRegistry: "gcr.io/myrepository"
|
||||
controllerManagerVersion: "v1.5.0-alpha.0.1010+892a6d7af59c0b"
|
||||
```
|
||||
|
||||
Assuming you have built and pushed the `hyperkube` image to the repository
|
||||
with the given tag in the example above.
|
||||
|
||||
### Getting images
|
||||
|
||||
To run the federation control plane components as pods, you first need the
|
||||
images for all the components. You can either use the official release
|
||||
images or you can build them yourself from HEAD.
|
||||
|
||||
### Using official release images
|
||||
|
||||
As part of every Kubernetes release, official release images are pushed to
|
||||
`k8s.gcr.io`. To use the images in this repository, you can
|
||||
set the container image fields in the following configs to point to the
|
||||
images in this repository. `k8s.gcr.io/hyperkube` image
|
||||
includes the federation-apiserver and federation-controller-manager
|
||||
binaries, so you can point the corresponding configs for those components
|
||||
to the hyperkube image.
|
||||
|
||||
### Building and pushing images from HEAD
|
||||
|
||||
To build the binaries, check out the
|
||||
[Kubernetes repository](https://github.com/kubernetes/kubernetes) and
|
||||
run the following commands from the root of the source directory:
|
||||
|
||||
|
||||
```shell
|
||||
$ federation/develop/develop.sh build_binaries
|
||||
```
|
||||
|
||||
To build the image and push it to the repository, run:
|
||||
|
||||
```shell
|
||||
$ KUBE_REGISTRY="gcr.io/myrepository" federation/develop/develop.sh build_image
|
||||
$ KUBE_REGISTRY="gcr.io/myrepository" federation/develop/develop.sh push
|
||||
```
|
||||
|
||||
Note: This is going to overwrite the values you might have set for
|
||||
`apiserverRegistry`, `apiserverVersion`, `controllerManagerRegistry` and
|
||||
`controllerManagerVersion` in your `${FEDERATION_OUTPUT_ROOT}/values.yaml`
|
||||
file. Hence, it is not recommended to customize these values in
|
||||
`${FEDERATION_OUTPUT_ROOT}/values.yaml` if you are building the
|
||||
images from source.
|
||||
|
||||
### Running the federation control plane
|
||||
|
||||
Once you have the images, you can turn up the federation control plane by
|
||||
running:
|
||||
|
||||
```shell
|
||||
$ federation/deploy/deploy.sh deploy_federation
|
||||
```
|
||||
|
||||
This spins up the federation control components as pods managed by
|
||||
[`Deployments`](/docs/concepts/workloads/controllers/deployment/) on your
|
||||
existing Kubernetes cluster. It also starts a
|
||||
[`type: LoadBalancer`](/docs/concepts/services-networking/service/#type-loadbalancer)
|
||||
[`Service`](/docs/concepts/services-networking/service/) for the
|
||||
`federation-apiserver` and a
|
||||
[`PVC`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims/) backed
|
||||
by a dynamically provisioned
|
||||
[`PV`](/docs/concepts/storage/persistent-volumes/) for
|
||||
`etcd`. All these components are created in the `federation` namespace.
|
||||
|
||||
You can verify that the pods are available by running the following
|
||||
command:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployments --namespace=federation
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
federation-apiserver 1 1 1 1 1m
|
||||
federation-controller-manager 1 1 1 1 1m
|
||||
```
|
||||
|
||||
Running `deploy.sh` also creates a new record in your kubeconfig for us
|
||||
to be able to talk to federation apiserver. You can view this by running
|
||||
`kubectl config view`.
|
||||
|
||||
Note: Dynamic provisioning for persistent volume currently works only on
|
||||
AWS, Google Kubernetes Engine, and GCE. However, you can edit the created `Deployments` to suit
|
||||
your needs, if required.
|
||||
|
||||
## Registering Kubernetes clusters with federation
|
||||
|
||||
Now that you have the federation control plane up and running, you can start registering Kubernetes clusters.
|
||||
|
||||
First of all, you need to create a secret containing kubeconfig for that Kubernetes cluster, which federation control plane will use to talk to that Kubernetes cluster.
|
||||
For now, you can create this secret in the host Kubernetes cluster (that hosts federation control plane). When federation starts supporting secrets, you will be able to create this secret there.
|
||||
Suppose that your kubeconfig for Kubernetes cluster is at `/cluster1/kubeconfig`, you can run the following command to create the secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic cluster1 --namespace=federation --from-file=/cluster1/kubeconfig
|
||||
```
|
||||
|
||||
Note that the file name should be `kubeconfig` since file name determines the name of the key in the secret.
|
||||
|
||||
Now that the secret is created, you are ready to register the cluster. The YAML file for cluster will look like:
|
||||
|
||||
```yaml
|
||||
apiVersion: federation/v1beta1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: cluster1
|
||||
spec:
|
||||
serverAddressByClientCIDRs:
|
||||
- clientCIDR: <client-cidr>
|
||||
serverAddress: <apiserver-address>
|
||||
secretRef:
|
||||
name: <secret-name>
|
||||
```
|
||||
|
||||
You need to insert the appropriate values for `<client-cidr>`, `<apiserver-address>` and `<secret-name>`.
|
||||
`<secret-name>` here is name of the secret that you just created.
|
||||
serverAddressByClientCIDRs contains the various server addresses that clients
|
||||
can use as per their CIDR. You can set the server's public IP address with CIDR
|
||||
`"0.0.0.0/0"` which all clients will match. In addition, if you want internal
|
||||
clients to use server's clusterIP, you can set that as serverAddress. The client
|
||||
CIDR in that case will be a CIDR that only matches IPs of pods running in that
|
||||
cluster.
|
||||
|
||||
Assuming your YAML file is located at `/cluster1/cluster.yaml`, you can run the following command to register this cluster:
|
||||
|
||||
<!-- TODO(madhusudancs): Make the kubeconfig context configurable with default set to `federation` -->
|
||||
```shell
|
||||
$ kubectl create -f /cluster1/cluster.yaml --context=federation-cluster
|
||||
|
||||
```
|
||||
|
||||
By specifying `--context=federation-cluster`, you direct the request to
|
||||
federation apiserver. You can ensure that the cluster registration was
|
||||
successful by running:
|
||||
|
||||
```shell
|
||||
$ kubectl get clusters --context=federation-cluster
|
||||
NAME STATUS VERSION AGE
|
||||
cluster1 Ready 3m
|
||||
```
|
||||
|
||||
## Updating KubeDNS
|
||||
|
||||
Once you've registered your cluster with the federation, you'll need to update KubeDNS so that your cluster can route federation service requests. The update method varies depending on your Kubernetes version; on Kubernetes 1.5 or later, you must pass the
|
||||
`--federations` flag to kube-dns via the kube-dns config map. In version 1.4 or earlier, you must set the `--federations` flag directly on kube-dns-rc on other clusters.
|
||||
|
||||
### Kubernetes 1.5+: Passing federations flag via config map to kube-dns
|
||||
|
||||
For Kubernetes clusters of version 1.5+, you can pass the
|
||||
`--federations` flag to kube-dns via the kube-dns config map.
|
||||
The flag uses the following format:
|
||||
|
||||
```
|
||||
--federations=${FEDERATION_NAME}=${DNS_DOMAIN_NAME}
|
||||
```
|
||||
|
||||
To pass this flag to KubeDNS, create a config-map with name `kube-dns` in
|
||||
namespace `kube-system`. The configmap should look like the following:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kube-dns
|
||||
namespace: kube-system
|
||||
data:
|
||||
federations: <federation-name>=<federation-domain-name>
|
||||
```
|
||||
|
||||
where `<federation-name>` should be replaced by the name you want to give to your
|
||||
federation, and
|
||||
`federation-domain-name` should be replaced by the domain name you want to use
|
||||
in your federation DNS.
|
||||
|
||||
You can find more details about config maps in general at
|
||||
[config map](/docs/tasks/configure-pod-container/configure-pod-configmap/).
|
||||
|
||||
### Kubernetes 1.4 and earlier: Setting federations flag on kube-dns-rc
|
||||
|
||||
If your cluster is running Kubernetes version 1.4 or earlier, you must restart
|
||||
KubeDNS and pass it a `--federations` flag, which tells it about valid federation DNS hostnames.
|
||||
The flag uses the following format:
|
||||
|
||||
```
|
||||
--federations=${FEDERATION_NAME}=${DNS_DOMAIN_NAME}
|
||||
```
|
||||
|
||||
To update KubeDNS with the `--federations` flag, you can edit the existing kubedns replication controller to
|
||||
include that flag in pod template spec, and then delete the existing pod. The replication controller then
|
||||
recreates the pod with updated template.
|
||||
|
||||
To find the name of existing kubedns replication controller, run the following command:
|
||||
|
||||
```shell
|
||||
$ kubectl get rc --namespace=kube-system
|
||||
```
|
||||
|
||||
You should see a list of all the replication controllers on the cluster. The kube-dns replication
|
||||
controller should have a name similar to `kube-dns-v18`. To edit the replication controller, specify it by name as follows:
|
||||
|
||||
```shell
|
||||
$ kubectl edit rc <rc-name> --namespace=kube-system
|
||||
```
|
||||
In the resulting YAML file for the kube-dns replication controller, add the `--federations` flag as an argument to kube-dns container.
|
||||
|
||||
Then, you must delete the existing kube dns pod. You can find the pod by running:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=kube-system
|
||||
```
|
||||
|
||||
And then delete the appropriate pod by running:
|
||||
|
||||
```shell
|
||||
$ kubectl delete pods <pod-name> --namespace=kube-system
|
||||
```
|
||||
|
||||
Once you've completed the kube-dns configuration, your federation is ready for use.
|
||||
|
||||
## Turn down
|
||||
|
||||
In order to turn the federation control plane down run the following
|
||||
command:
|
||||
|
||||
```shell
|
||||
$ federation/deploy/deploy.sh destroy_federation
|
||||
```
|
||||
|
||||
## Previous Federation turn up mechanism
|
||||
|
||||
This describes the previous mechanism we had to turn up Kubernetes Cluster
|
||||
Federation. It is recommended to use the new turn up mechanism. If you would
|
||||
like to use this mechanism instead of the new one, please let us know
|
||||
why the new mechanism doesn't work for your case by filing an issue here -
|
||||
[https://github.com/kubernetes/kubernetes/issues/new](https://github.com/kubernetes/kubernetes/issues/new)
|
||||
|
||||
### Getting images
|
||||
|
||||
To run these as pods, you first need images for all the components. You can use
|
||||
official release images or you can build from HEAD.
|
||||
|
||||
#### Using official release images
|
||||
|
||||
As part of every release, images are pushed to `staging-k8s.gcr.io`, which are
|
||||
re-published through `k8s.gcr.io` (which is globally replicated). To use
|
||||
these images, set env var `FEDERATION_PUSH_REPO_BASE=k8s.gcr.io`
|
||||
This will always use the latest image.
|
||||
To use the hyperkube image which includes federation-apiserver and
|
||||
federation-controller-manager from a specific release, set the
|
||||
`FEDERATION_IMAGE_TAG` environment variable.
|
||||
|
||||
#### Building and pushing images from HEAD
|
||||
|
||||
To run the code from HEAD, you need to build and push your own images.
|
||||
You can build the images using the following command:
|
||||
|
||||
```shell
|
||||
$ FEDERATION=true KUBE_RELEASE_RUN_TESTS=n make quick-release
|
||||
```
|
||||
|
||||
Next, you need to push these images to a registry such as Google Container Registry or Docker Hub, so that your cluster can pull them.
|
||||
If Kubernetes cluster is running on Google Compute Engine (GCE), then you can push the images to `gcr.io/<gce-project-name>`.
|
||||
The command to push the images will look like:
|
||||
|
||||
```shell
|
||||
$ FEDERATION=true FEDERATION_PUSH_REPO_BASE=gcr.io/<gce-project-name> ./build/push-federation-images.sh
|
||||
```
|
||||
|
||||
### Running the federation control plane
|
||||
|
||||
Once you have the images, you can run these as pods on your existing kubernetes cluster.
|
||||
The command to run these pods on an existing GCE cluster will look like:
|
||||
|
||||
```shell
|
||||
$ KUBERNETES_PROVIDER=gce FEDERATION_DNS_PROVIDER=google-clouddns FEDERATION_NAME=myfederation DNS_ZONE_NAME=myfederation.example FEDERATION_PUSH_REPO_BASE=k8s.gcr.io ./federation/cluster/federation-up.sh
|
||||
```
|
||||
|
||||
`KUBERNETES_PROVIDER` is the cloud provider.
|
||||
|
||||
`FEDERATION_DNS_PROVIDER` can be `google-clouddns` or `aws-route53`. It will be
|
||||
set appropriately if it is missing and `KUBERNETES_PROVIDER` is one of `gce`, `gke` and `aws`.
|
||||
This is used to resolve DNS requests for federation services. The service
|
||||
controller keeps DNS records with the provider updated as services/pods are
|
||||
updated in underlying Kubernetes clusters.
|
||||
|
||||
`FEDERATION_NAME` is a name you can choose for your federation. This is the name that will appear in DNS routes.
|
||||
|
||||
`DNS_ZONE_NAME` is the domain to be used for DNS records. This is a domain that you
|
||||
need to buy and then configure it such that DNS queries for that domain are
|
||||
routed to the appropriate provider as per `FEDERATION_DNS_PROVIDER`.
|
||||
|
||||
Running that command creates a namespace `federation` and creates 2 deployments: `federation-apiserver` and `federation-controller-manager`.
|
||||
You can verify that the pods are available by running the following command:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployments --namespace=federation
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
federation-apiserver 1 1 1 1 1m
|
||||
federation-controller-manager 1 1 1 1 1m
|
||||
```
|
||||
|
||||
Running `federation-up.sh` also creates a new record in your kubeconfig for us
|
||||
to be able to talk to federation apiserver. You can view this by running
|
||||
`kubectl config view`.
|
||||
|
||||
Note: `federation-up.sh` creates the federation-apiserver pod with an etcd
|
||||
container that is backed by a persistent volume, so as to persist data. This
|
||||
currently works only on AWS, Google Kubernetes Engine, and GCE. You can edit
|
||||
`federation/manifests/federation-apiserver-deployment.yaml` to suit your needs,
|
||||
if required.
|
||||
|
||||
|
||||
## For more information
|
||||
|
||||
* [Federation proposal](https://git.k8s.io/community/contributors/design-proposals/multicluster/federation.md) details use cases that motivated this work.
|
||||
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
---
|
||||
title: Building High-Availability Clusters
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
This document describes how to build a high-availability (HA) Kubernetes cluster. This is a fairly advanced topic.
|
||||
Users who merely want to experiment with Kubernetes are encouraged to use configurations that are simpler to set up such
|
||||
as [Minikube](/docs/getting-started-guides/minikube/)
|
||||
or try [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) for hosted Kubernetes.
|
||||
|
||||
Also, at this time high availability support for Kubernetes is not continuously tested in our end-to-end (e2e) testing. We will
|
||||
be working to add this continuous testing, but for now the single-node master installations are more heavily tested.
|
||||
|
||||
* TOC
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
Setting up a truly reliable, highly available distributed system requires a number of steps. It is akin to
|
||||
wearing underwear, pants, a belt, suspenders, another pair of underwear, and another pair of pants. We go into each
|
||||
of these steps in detail, but a summary is given here to help guide and orient the user.
|
||||
|
||||
The steps involved are as follows:
|
||||
|
||||
* [Creating the reliable constituent nodes that collectively form our HA master implementation.](#reliable-nodes)
|
||||
* [Setting up a redundant, reliable storage layer with clustered etcd.](#establishing-a-redundant-reliable-data-storage-layer)
|
||||
* [Starting replicated, load balanced Kubernetes API servers](#replicated-api-servers)
|
||||
* [Setting up master-elected Kubernetes scheduler and controller-manager daemons](#master-elected-components)
|
||||
|
||||
Here's what the system should look like when it's finished:
|
||||
|
||||

|
||||
|
||||
## Initial set-up
|
||||
|
||||
The remainder of this guide assumes that you are setting up a 3-node clustered master, where each machine is running some flavor of Linux.
|
||||
Examples in the guide are given for Debian distributions, but they should be easily adaptable to other distributions.
|
||||
Likewise, this set up should work whether you are running in a public or private cloud provider, or if you are running
|
||||
on bare metal.
|
||||
|
||||
The easiest way to implement an HA Kubernetes cluster is to start with an existing single-master cluster. The
|
||||
instructions at [https://get.k8s.io](https://get.k8s.io)
|
||||
describe easy installation for single-master clusters on a variety of platforms.
|
||||
|
||||
## Reliable nodes
|
||||
|
||||
On each master node, we are going to run a number of processes that implement the Kubernetes API. The first step in making these reliable is
|
||||
to make sure that each automatically restarts when it fails. To achieve this, we need to install a process watcher. We choose to use
|
||||
the `kubelet` that we run on each of the worker nodes. This is convenient, since we can use containers to distribute our binaries, we can
|
||||
establish resource limits, and introspect the resource usage of each daemon. Of course, we also need something to monitor the kubelet
|
||||
itself (insert who watches the watcher jokes here). For Debian systems, we choose monit, but there are a number of alternate
|
||||
choices. For example, on systemd-based systems (e.g. RHEL, CentOS), you can run 'systemctl enable kubelet'.
|
||||
|
||||
If you are extending from a standard Kubernetes installation, the `kubelet` binary should already be present on your system. You can run
|
||||
`which kubelet` to determine if the binary is in fact installed. If it is not installed,
|
||||
you should install the [kubelet binary](https://storage.googleapis.com/kubernetes-release/release/v0.19.3/bin/linux/amd64/kubelet) and [default-kubelet](/docs/admin/high-availability/default-kubelet)
|
||||
scripts.
|
||||
|
||||
If you are using monit, you should also install the monit daemon (`apt-get install monit`) and the [monit-kubelet](/docs/admin/high-availability/monit-kubelet) and
|
||||
[monit-docker](/docs/admin/high-availability/monit-docker) configs.
|
||||
|
||||
On systemd systems you `systemctl enable kubelet` and `systemctl enable docker`.
|
||||
|
||||
## Establishing a redundant, reliable data storage layer
|
||||
|
||||
The central foundation of a highly available solution is a redundant, reliable storage layer. The number one rule of high-availability is
|
||||
to protect the data. Whatever else happens, whatever catches on fire, if you have the data, you can rebuild. If you lose the data, you're
|
||||
done.
|
||||
|
||||
Clustered etcd already replicates your storage to all master instances in your cluster. This means that to lose data, all three nodes would need
|
||||
to have their physical (or virtual) disks fail at the same time. The probability that this occurs is relatively low, so for many people
|
||||
running a replicated etcd cluster is likely reliable enough. You can add additional reliability by increasing the
|
||||
size of the cluster from three to five nodes. If that is still insufficient, you can add
|
||||
[even more redundancy to your storage layer](#even-more-reliable-storage).
|
||||
|
||||
### Clustering etcd
|
||||
|
||||
The full details of clustering etcd are beyond the scope of this document, lots of details are given on the
|
||||
[etcd clustering page](https://github.com/coreos/etcd/blob/master/Documentation/op-guide/clustering.md). This example walks through
|
||||
a simple cluster set up, using etcd's built in discovery to build our cluster.
|
||||
|
||||
First, hit the etcd discovery service to create a new token:
|
||||
|
||||
```shell
|
||||
curl https://discovery.etcd.io/new?size=3
|
||||
```
|
||||
|
||||
On each node, copy the [etcd.yaml](/docs/admin/high-availability/etcd.yaml) file into `/etc/kubernetes/manifests/etcd.yaml`
|
||||
|
||||
The kubelet on each node actively monitors the contents of that directory, and it will create an instance of the `etcd`
|
||||
server from the definition of the pod specified in `etcd.yaml`.
|
||||
|
||||
Note that in `etcd.yaml` you should substitute the token URL you got above for `${DISCOVERY_TOKEN}` on all three machines,
|
||||
and you should substitute a different name (e.g. `node-1`) for `${NODE_NAME}` and the correct IP address
|
||||
for `${NODE_IP}` on each machine.
|
||||
|
||||
#### Validating your cluster
|
||||
|
||||
Once you copy this into all three nodes, you should have a clustered etcd set up. You can validate on master with
|
||||
|
||||
```shell
|
||||
kubectl exec <pod_name> etcdctl member list
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```shell
|
||||
kubectl exec <pod_name> etcdctl cluster-health
|
||||
```
|
||||
|
||||
You can also validate that this is working with `etcdctl set foo bar` on one node, and `etcdctl get foo`
|
||||
on a different node.
|
||||
|
||||
### Even more reliable storage
|
||||
|
||||
Of course, if you are interested in increased data reliability, there are further options which make the place where etcd
|
||||
installs its data even more reliable than regular disks (belts *and* suspenders, ftw!).
|
||||
|
||||
If you use a cloud provider, then they usually provide this
|
||||
for you, for example [Persistent Disk](https://cloud.google.com/compute/docs/disks/persistent-disks) on the Google Cloud Platform. These
|
||||
are block-device persistent storage that can be mounted onto your virtual machine. Other cloud providers provide similar solutions.
|
||||
|
||||
If you are running on physical machines, you can also use network attached redundant storage using an iSCSI or NFS interface.
|
||||
Alternatively, you can run a clustered file system like Gluster or Ceph. Finally, you can also run a RAID array on each physical machine.
|
||||
|
||||
Regardless of how you choose to implement it, if you chose to use one of these options, you should make sure that your storage is mounted
|
||||
to each machine. If your storage is shared between the three masters in your cluster, you should create a different directory on the storage
|
||||
for each node. Throughout these instructions, we assume that this storage is mounted to your machine in `/var/etcd/data`.
|
||||
|
||||
## Replicated API Servers
|
||||
|
||||
Once you have replicated etcd set up correctly, we will also install the apiserver using the kubelet.
|
||||
|
||||
### Installing configuration files
|
||||
|
||||
First you need to create the initial log file, so that Docker mounts a file instead of a directory:
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-apiserver.log
|
||||
```
|
||||
|
||||
Next, you need to create a `/srv/kubernetes/` directory on each node. This directory includes:
|
||||
|
||||
* basic_auth.csv - basic auth user and password
|
||||
* ca.crt - Certificate Authority cert
|
||||
* known_tokens.csv - tokens that entities (e.g. the kubelet) can use to talk to the apiserver
|
||||
* kubecfg.crt - Client certificate, public key
|
||||
* kubecfg.key - Client certificate, private key
|
||||
* server.cert - Server certificate, public key
|
||||
* server.key - Server certificate, private key
|
||||
|
||||
The easiest way to create this directory, may be to copy it from the master node of a working cluster, or you can manually generate these files yourself.
|
||||
|
||||
### Starting the API Server
|
||||
|
||||
Once these files exist, copy the [kube-apiserver.yaml](/docs/admin/high-availability/kube-apiserver.yaml) into `/etc/kubernetes/manifests/` on each master node.
|
||||
|
||||
The kubelet monitors this directory, and will automatically create an instance of the `kube-apiserver` container using the pod definition specified
|
||||
in the file.
|
||||
|
||||
### Load balancing
|
||||
|
||||
At this point, you should have 3 apiservers all working correctly. If you set up a network load balancer, you should
|
||||
be able to access your cluster via that load balancer, and see traffic balancing between the apiserver instances. Setting
|
||||
up a load balancer will depend on the specifics of your platform, for example instructions for the Google Cloud
|
||||
Platform can be found [here](https://cloud.google.com/compute/docs/load-balancing/).
|
||||
|
||||
Note, if you are using authentication, you may need to regenerate your certificate to include the IP address of the balancer,
|
||||
in addition to the IP addresses of the individual nodes.
|
||||
|
||||
For pods that you deploy into the cluster, the `kubernetes` service/dns name should provide a load balanced endpoint for the master automatically.
|
||||
|
||||
For external users of the API (e.g. the `kubectl` command line interface, continuous build pipelines, or other clients) you will want to configure
|
||||
them to talk to the external load balancer's IP address.
|
||||
|
||||
### Endpoint reconciler
|
||||
|
||||
As mentioned in the previous section, the apiserver is exposed through a
|
||||
service called `kubernetes`. The endpoints for this service correspond to
|
||||
the apiserver replicas that we just deployed.
|
||||
|
||||
Since updating endpoints and services requires the apiserver to be up, there
|
||||
is special code in the apiserver to let it update its own endpoints directly.
|
||||
This code is called the "reconciler," because it reconciles the list of
|
||||
endpoints stored in etcd, and the list of endpoints that are actually up
|
||||
and running.
|
||||
|
||||
Prior to Kubernetes 1.9, the reconciler expects you to provide the
|
||||
number of endpoints (i.e., the number of apiserver replicas) through
|
||||
a command-line flag (e.g. `--apiserver-count=3`). If more replicas
|
||||
are available, the reconciler trims down the list of endpoints.
|
||||
As a result, if a node running a replica of the apiserver crashes
|
||||
and gets replaced, the list of endpoints is eventually updated.
|
||||
However, until the replica gets replaced, its endpoint stays in
|
||||
the list. During that time, a fraction of the API requests sent
|
||||
to the `kubernetes` service will fail, because they will be sent
|
||||
to a down endpoint.
|
||||
|
||||
This is why the previous section advises you to deploy a load
|
||||
balancer, and access the API through that load balancer. The
|
||||
load balancer will directly assess the health of the apiserver
|
||||
replicas, and make sure that requests are not sent to crashed
|
||||
instances.
|
||||
|
||||
If you do not add the `--apiserver-count` flag, the value defaults to 1.
|
||||
Your cluster will work correctly, but each apiserver replica will
|
||||
continuously try to add itself to the list of endpoints while removing
|
||||
the other ones, causing a lot of extraneous updates in kube-proxy
|
||||
and other components.
|
||||
|
||||
Starting with Kubernetes 1.9, a new alpha reconciler implementation is
|
||||
available. It uses a *lease* that is regularly renewed by each apiserver
|
||||
replica. When a replica is down, it stops renewing its lease, and the other
|
||||
replicas notice that the lease expired and remove it from the list of
|
||||
endpoints. You can switch to the new reconciler by adding the flag
|
||||
`--endpoint-reconciler-type=lease` when starting your apiserver replicas.
|
||||
|
||||
{{< feature-state state="alpha" >}}
|
||||
|
||||
If you want to know more, you can check the following resources:
|
||||
- [issue kubernetes/kubernetes#22609](https://github.com/kubernetes/kubernetes/issues/22609),
|
||||
which gives additional context
|
||||
- [master/reconcilers/mastercount.go](https://github.com/kubernetes/kubernetes/blob/dd9981d038012c120525c9e6df98b3beb3ef19e1/pkg/master/reconcilers/mastercount.go#L63),
|
||||
the implementation of the master count reconciler
|
||||
- [PR kubernetes/kubernetes#51698](https://github.com/kubernetes/kubernetes/pull/51698),
|
||||
which adds support for the lease reconciler
|
||||
|
||||
## Master elected components
|
||||
|
||||
So far we have set up state storage, and we have set up the API server, but we haven't run anything that actually modifies
|
||||
cluster state, such as the controller manager and scheduler. To achieve this reliably, we only want to have one actor modifying state at a time, but we want replicated
|
||||
instances of these actors, in case a machine dies. To achieve this, we are going to use a lease-lock in the API to perform
|
||||
master election. We will use the `--leader-elect` flag for each scheduler and controller-manager, using a lease in the API will ensure that only 1 instance of the scheduler and controller-manager are running at once.
|
||||
|
||||
The scheduler and controller-manager can be configured to talk to the API server that is on the same node (i.e. 127.0.0.1), or it can be configured to communicate using the load balanced IP address of the API servers. Regardless of how they are configured, the scheduler and controller-manager will complete the leader election process mentioned above when using the `--leader-elect` flag.
|
||||
|
||||
In case of a failure accessing the API server, the elected leader will not be able to renew the lease, causing a new leader to be elected. This is especially relevant when configuring the scheduler and controller-manager to access the API server via 127.0.0.1, and the API server on the same node is unavailable.
|
||||
|
||||
### Installing configuration files
|
||||
|
||||
First, create empty log files on each node, so that Docker will mount the files not make new directories:
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-scheduler.log
|
||||
touch /var/log/kube-controller-manager.log
|
||||
```
|
||||
|
||||
Next, set up the descriptions of the scheduler and controller manager pods on each node by copying [kube-scheduler.yaml](/docs/admin/high-availability/kube-scheduler.yaml) and [kube-controller-manager.yaml](/docs/admin/high-availability/kube-controller-manager.yaml) into the `/etc/kubernetes/manifests/` directory.
|
||||
|
||||
## Conclusion
|
||||
|
||||
At this point, you are done (yeah!) with the master components, but you still need to add worker nodes (boo!).
|
||||
|
||||
If you have an existing cluster, this is as simple as reconfiguring your kubelets to talk to the load-balanced endpoint, and
|
||||
restarting the kubelets on each node.
|
||||
|
||||
If you are turning up a fresh cluster, you will need to install the kubelet and kube-proxy on each worker node, and
|
||||
set the `--apiserver` flag to your replicated endpoint.
|
||||
@@ -0,0 +1,8 @@
|
||||
# This should be the IP address of the load balancer for all masters
|
||||
MASTER_IP=<insert-ip-here>
|
||||
# This should be the internal service IP address reserved for DNS
|
||||
DNS_IP=<insert-dns-ip-here>
|
||||
|
||||
DAEMON_ARGS="$DAEMON_ARGS --api-servers=https://${MASTER_IP} --enable-debugging-handlers=true --cloud-provider=
|
||||
gce --pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=False --v=2 --cluster-dns=${DNS_IP} --cluster-domain=c
|
||||
luster.local --configure-cbr0=true --cgroup-root=/ --system-container=/system "
|
||||
@@ -0,0 +1,87 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: etcd-server
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- image: k8s.gcr.io/etcd:3.0.17
|
||||
name: etcd-container
|
||||
command:
|
||||
- /usr/local/bin/etcd
|
||||
- --name
|
||||
- ${NODE_NAME}
|
||||
- --initial-advertise-peer-urls
|
||||
- http://${NODE_IP}:2380
|
||||
- --listen-peer-urls
|
||||
- http://${NODE_IP}:2380
|
||||
- --advertise-client-urls
|
||||
- http://${NODE_IP}:4001
|
||||
- --listen-client-urls
|
||||
- http://127.0.0.1:4001
|
||||
- --data-dir
|
||||
- /var/etcd/data
|
||||
- --discovery
|
||||
- ${DISCOVERY_TOKEN}
|
||||
ports:
|
||||
- containerPort: 2380
|
||||
hostPort: 2380
|
||||
name: serverport
|
||||
- containerPort: 4001
|
||||
hostPort: 4001
|
||||
name: clientport
|
||||
volumeMounts:
|
||||
- mountPath: /var/etcd
|
||||
name: varetcd
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/etcd/data
|
||||
name: varetcd
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
@@ -0,0 +1,90 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-apiserver
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: kube-apiserver
|
||||
image: k8s.gcr.io/kube-apiserver:9680e782e08a1a1c94c656190011bd02
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-apiserver --address=127.0.0.1 --etcd-servers=http://127.0.0.1:4001
|
||||
--cloud-provider=gce --enable-admission-plugins=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
|
||||
--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
|
||||
--tls-cert-file=/srv/kubernetes/server.cert --tls-private-key-file=/srv/kubernetes/server.key
|
||||
--secure-port=443 --token-auth-file=/srv/kubernetes/known_tokens.csv --v=2
|
||||
--allow-privileged=False 1>>/var/log/kube-apiserver.log 2>&1
|
||||
ports:
|
||||
- containerPort: 443
|
||||
hostPort: 443
|
||||
name: https
|
||||
- containerPort: 7080
|
||||
hostPort: 7080
|
||||
name: http
|
||||
- containerPort: 8080
|
||||
hostPort: 8080
|
||||
name: local
|
||||
volumeMounts:
|
||||
- mountPath: /srv/kubernetes
|
||||
name: srvkube
|
||||
readOnly: true
|
||||
- mountPath: /var/log/kube-apiserver.log
|
||||
name: logfile
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: srvkube
|
||||
- hostPath:
|
||||
path: /var/log/kube-apiserver.log
|
||||
name: logfile
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
@@ -0,0 +1,82 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-controller-manager --master=127.0.0.1:8080 --cluster-name=e2e-test-bburns
|
||||
--cluster-cidr=10.245.0.0/16 --allocate-node-cidrs=true --cloud-provider=gce --service-account-private-key-file=/srv/kubernetes/server.key
|
||||
--v=2 --leader-elect=true 1>>/var/log/kube-controller-manager.log 2>&1
|
||||
image: k8s.gcr.io/kube-controller-manager:fda24638d51a48baa13c35337fcd4793
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10252
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
name: kube-controller-manager
|
||||
volumeMounts:
|
||||
- mountPath: /srv/kubernetes
|
||||
name: srvkube
|
||||
readOnly: true
|
||||
- mountPath: /var/log/kube-controller-manager.log
|
||||
name: logfile
|
||||
- mountPath: /etc/ssl
|
||||
name: etcssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
readOnly: true
|
||||
- mountPath: /var/ssl
|
||||
name: varssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/ssl
|
||||
name: usrssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
readOnly: true
|
||||
- mountPath: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/openssl
|
||||
name: etcopenssl
|
||||
readOnly: true
|
||||
- mountPath: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
readOnly: true
|
||||
hostNetwork: true
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: srvkube
|
||||
- hostPath:
|
||||
path: /var/log/kube-controller-manager.log
|
||||
name: logfile
|
||||
- hostPath:
|
||||
path: /etc/ssl
|
||||
name: etcssl
|
||||
- hostPath:
|
||||
path: /usr/share/ssl
|
||||
name: usrsharessl
|
||||
- hostPath:
|
||||
path: /var/ssl
|
||||
name: varssl
|
||||
- hostPath:
|
||||
path: /usr/ssl
|
||||
name: usrssl
|
||||
- hostPath:
|
||||
path: /usr/lib/ssl
|
||||
name: usrlibssl
|
||||
- hostPath:
|
||||
path: /usr/local/openssl
|
||||
name: usrlocalopenssl
|
||||
- hostPath:
|
||||
path: /etc/openssl
|
||||
name: etcopenssl
|
||||
- hostPath:
|
||||
path: /etc/pki/tls
|
||||
name: etcpkitls
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: kube-scheduler
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: kube-scheduler
|
||||
image: k8s.gcr.io/kube-scheduler:34d0b8f8b31e27937327961528739bc9
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- /usr/local/bin/kube-scheduler --master=127.0.0.1:8080 --v=2 --leader-elect=true 1>>/var/log/kube-scheduler.log
|
||||
2>&1
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10251
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
volumeMounts:
|
||||
- mountPath: /var/log/kube-scheduler.log
|
||||
name: logfile
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /var/log/kube-scheduler.log
|
||||
name: logfile
|
||||
@@ -0,0 +1,9 @@
|
||||
check process docker with pidfile /var/run/docker.pid
|
||||
group docker
|
||||
start program = "/etc/init.d/docker start"
|
||||
stop program = "/etc/init.d/docker stop"
|
||||
if does not exist then restart
|
||||
if failed
|
||||
unixsocket /var/run/docker.sock
|
||||
protocol HTTP request "/version"
|
||||
then restart
|
||||
@@ -0,0 +1,11 @@
|
||||
check process kubelet with pidfile /var/run/kubelet.pid
|
||||
group kubelet
|
||||
start program = "/etc/init.d/kubelet start"
|
||||
stop program = "/etc/init.d/kubelet stop"
|
||||
if does not exist then restart
|
||||
if failed
|
||||
host 127.0.0.1
|
||||
port 10255
|
||||
protocol HTTP
|
||||
request "/healthz"
|
||||
then restart
|
||||
@@ -0,0 +1,43 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: scheduler-master
|
||||
spec:
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: scheduler-elector
|
||||
image: k8s.gcr.io/podmaster:1.1
|
||||
command:
|
||||
- /podmaster
|
||||
- --etcd-servers=http://127.0.0.1:4001
|
||||
- --key=scheduler
|
||||
- --source-file=/kubernetes/kube-scheduler.manifest
|
||||
- --dest-file=/manifests/kube-scheduler.manifest
|
||||
volumeMounts:
|
||||
- mountPath: /kubernetes
|
||||
name: k8s
|
||||
readOnly: true
|
||||
- mountPath: /manifests
|
||||
name: manifests
|
||||
- name: controller-manager-elector
|
||||
image: k8s.gcr.io/podmaster:1.1
|
||||
command:
|
||||
- /podmaster
|
||||
- --etcd-servers=http://127.0.0.1:4001
|
||||
- --key=controller
|
||||
- --source-file=/kubernetes/kube-controller-manager.manifest
|
||||
- --dest-file=/manifests/kube-controller-manager.manifest
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
- mountPath: /kubernetes
|
||||
name: k8s
|
||||
readOnly: true
|
||||
- mountPath: /manifests
|
||||
name: manifests
|
||||
volumes:
|
||||
- hostPath:
|
||||
path: /srv/kubernetes
|
||||
name: k8s
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/manifests
|
||||
name: manifests
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
reviewers:
|
||||
- liggitt
|
||||
title: Kubelet authentication/authorization
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
A kubelet's HTTPS endpoint exposes APIs which give access to data of varying sensitivity,
|
||||
and allow you to perform operations with varying levels of power on the node and within containers.
|
||||
|
||||
This document describes how to authenticate and authorize access to the kubelet's HTTPS endpoint.
|
||||
|
||||
## Kubelet authentication
|
||||
|
||||
By default, requests to the kubelet's HTTPS endpoint that are not rejected by other configured
|
||||
authentication methods are treated as anonymous requests, and given a username of `system:anonymous`
|
||||
and a group of `system:unauthenticated`.
|
||||
|
||||
To disable anonymous access and send `401 Unauthorized` responses to unauthenticated requests:
|
||||
|
||||
* start the kubelet with the `--anonymous-auth=false` flag
|
||||
|
||||
To enable X509 client certificate authentication to the kubelet's HTTPS endpoint:
|
||||
|
||||
* start the kubelet with the `--client-ca-file` flag, providing a CA bundle to verify client certificates with
|
||||
* start the apiserver with `--kubelet-client-certificate` and `--kubelet-client-key` flags
|
||||
* see the [apiserver authentication documentation](/docs/admin/authentication/#x509-client-certs) for more details
|
||||
|
||||
To enable API bearer tokens (including service account tokens) to be used to authenticate to the kubelet's HTTPS endpoint:
|
||||
|
||||
* ensure the `authentication.k8s.io/v1beta1` API group is enabled in the API server
|
||||
* start the kubelet with the `--authentication-token-webhook` and `--kubeconfig` flags
|
||||
* the kubelet calls the `TokenReview` API on the configured API server to determine user information from bearer tokens
|
||||
|
||||
## Kubelet authorization
|
||||
|
||||
Any request that is successfully authenticated (including an anonymous request) is then authorized. The default authorization mode is `AlwaysAllow`, which allows all requests.
|
||||
|
||||
There are many possible reasons to subdivide access to the kubelet API:
|
||||
|
||||
* anonymous auth is enabled, but anonymous users' ability to call the kubelet API should be limited
|
||||
* bearer token auth is enabled, but arbitrary API users' (like service accounts) ability to call the kubelet API should be limited
|
||||
* client certificate auth is enabled, but only some of the client certificates signed by the configured CA should be allowed to use the kubelet API
|
||||
|
||||
To subdivide access to the kubelet API, delegate authorization to the API server:
|
||||
|
||||
* ensure the `authorization.k8s.io/v1beta1` API group is enabled in the API server
|
||||
* start the kubelet with the `--authorization-mode=Webhook` and the `--kubeconfig` flags
|
||||
* the kubelet calls the `SubjectAccessReview` API on the configured API server to determine whether each request is authorized
|
||||
|
||||
The kubelet authorizes API requests using the same [request attributes](/docs/admin/authorization/#request-attributes) approach as the apiserver.
|
||||
|
||||
The verb is determined from the incoming request's HTTP verb:
|
||||
|
||||
HTTP verb | request verb
|
||||
----------|---------------
|
||||
POST | create
|
||||
GET, HEAD | get
|
||||
PUT | update
|
||||
PATCH | patch
|
||||
DELETE | delete
|
||||
|
||||
The resource and subresource is determined from the incoming request's path:
|
||||
|
||||
Kubelet API | resource | subresource
|
||||
-------------|----------|------------
|
||||
/stats/\* | nodes | stats
|
||||
/metrics/\* | nodes | metrics
|
||||
/logs/\* | nodes | log
|
||||
/spec/\* | nodes | spec
|
||||
*all others* | nodes | proxy
|
||||
|
||||
The namespace and API group attributes are always an empty string, and
|
||||
the resource name is always the name of the kubelet's `Node` API object.
|
||||
|
||||
When running in this mode, ensure the user identified by the `--kubelet-client-certificate` and `--kubelet-client-key`
|
||||
flags passed to the apiserver is authorized for the following attributes:
|
||||
|
||||
* verb=\*, resource=nodes, subresource=proxy
|
||||
* verb=\*, resource=nodes, subresource=stats
|
||||
* verb=\*, resource=nodes, subresource=log
|
||||
* verb=\*, resource=nodes, subresource=spec
|
||||
* verb=\*, resource=nodes, subresource=metrics
|
||||
@@ -0,0 +1,222 @@
|
||||
---
|
||||
reviewers:
|
||||
- ericchiang
|
||||
- mikedanese
|
||||
- jcbsmpsn
|
||||
title: TLS bootstrapping
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how to set up TLS client certificate bootstrapping for kubelets.
|
||||
Kubernetes 1.4 introduced an API for requesting certificates from a cluster-level Certificate Authority (CA). The original intent of this API is to enable provisioning of TLS client certificates for kubelets. The proposal can be found [here](https://github.com/kubernetes/kubernetes/pull/20439)
|
||||
and progress on the feature is being tracked as [feature #43](https://github.com/kubernetes/features/issues/43).
|
||||
|
||||
## kube-apiserver configuration
|
||||
|
||||
The API server should be configured with an [authenticator](/docs/admin/authentication/) that can authenticate tokens as a user in the `system:bootstrappers` group.
|
||||
|
||||
This group will later be used in the controller-manager configuration to scope approvals in the default approval
|
||||
controller. As this feature matures, you should ensure tokens are bound to a Role-Based Access Control (RBAC) policy which limits requests
|
||||
(using the bootstrap token) strictly to client requests related to certificate provisioning. With RBAC in place, scoping the tokens to a group allows for great flexibility (e.g. you could disable a particular bootstrap group's access when you are done provisioning the nodes).
|
||||
|
||||
While any authentication strategy can be used for the kubelet's initial bootstrap credentials, the following two authenticators are recommended for ease of provisioning.
|
||||
|
||||
1. [Bootstrap Tokens](/docs/admin/bootstrap-tokens/) - __alpha__
|
||||
2. [Token authentication file](#token-authentication-file)
|
||||
|
||||
Using bootstrap tokens is currently __alpha__ and will simplify the management of bootstrap token management especially in a HA scenario.
|
||||
|
||||
### Token authentication file
|
||||
Tokens are arbitrary but should represent at least 128 bits of entropy derived from a secure random number
|
||||
generator (such as /dev/urandom on most modern systems). There are multiple ways you can generate a token. For example:
|
||||
|
||||
`head -c 16 /dev/urandom | od -An -t x | tr -d ' '`
|
||||
|
||||
will generate tokens that look like `02b50b05283e98dd0fd71db496ef01e8`
|
||||
|
||||
The token file should look like the following example, where the first three values can be anything and the quoted group
|
||||
name should be as depicted:
|
||||
|
||||
```
|
||||
02b50b05283e98dd0fd71db496ef01e8,kubelet-bootstrap,10001,"system:bootstrappers"
|
||||
```
|
||||
|
||||
Add the `--token-auth-file=FILENAME` flag to the kube-apiserver command (in your systemd unit file perhaps) to enable the token file.
|
||||
See docs [here](/docs/admin/authentication/#static-token-file) for further details.
|
||||
|
||||
### Client certificate CA bundle
|
||||
|
||||
Add the `--client-ca-file=FILENAME` flag to the kube-apiserver command to enable client certificate authentication,
|
||||
referencing a certificate authority bundle containing the signing certificate (e.g. `--client-ca-file=/var/lib/kubernetes/ca.pem`).
|
||||
|
||||
## kube-controller-manager configuration
|
||||
The API for requesting certificates adds a certificate-issuing control loop to the Kubernetes Controller Manager. This takes the form of a
|
||||
[cfssl](https://blog.cloudflare.com/introducing-cfssl/) local signer using assets on disk. Currently, all certificates issued have one year validity and a default set of key usages.
|
||||
|
||||
### Signing assets
|
||||
You must provide a Certificate Authority in order to provide the cryptographic materials necessary to issue certificates.
|
||||
This CA should be trusted by kube-apiserver for authentication with the `--client-ca-file=FILENAME` flag. The management
|
||||
of the CA is beyond the scope of this document but it is recommended that you generate a dedicated CA for Kubernetes.
|
||||
Both certificate and key are assumed to be PEM-encoded.
|
||||
|
||||
The kube-controller-manager flags are:
|
||||
|
||||
```
|
||||
--cluster-signing-cert-file="/etc/path/to/kubernetes/ca/ca.crt" --cluster-signing-key-file="/etc/path/to/kubernetes/ca/ca.key"
|
||||
```
|
||||
|
||||
### Approval controller
|
||||
|
||||
In 1.7 the experimental "group auto approver" controller is dropped in favor of the new `csrapproving` controller
|
||||
that ships as part of [kube-controller-manager](/docs/admin/kube-controller-manager/) and is enabled by default.
|
||||
The controller uses the [`SubjectAccessReview` API](/docs/admin/authorization/#checking-api-access) to determine
|
||||
if a given user is authorized to request a CSR, then approves based on the authorization outcome. To prevent
|
||||
conflicts with other approvers, the builtin approver doesn't explicitly deny CSRs, only ignoring unauthorized requests.
|
||||
|
||||
The controller categorizes CSRs into three subresources:
|
||||
|
||||
1. `nodeclient` - a request by a user for a client certificate with `O=system:nodes` and `CN=system:node:(node name)`.
|
||||
2. `selfnodeclient` - a node renewing a client certificate with the same `O` and `CN`.
|
||||
3. `selfnodeserver` - a node renewing a serving certificate. (ALPHA, requires feature gate)
|
||||
|
||||
The checks to determine if a CSR is a `selfnodeserver` request is currently tied to the kubelet's credential rotation
|
||||
implementation, an __alpha__ feature. As such, the definition of `selfnodeserver` will likely change in a future and
|
||||
requires the `RotateKubeletServerCertificate` feature gate on the controller manager. The feature progress can be
|
||||
tracked at [kubernetes/features#267](https://github.com/kubernetes/features/issues/267).
|
||||
|
||||
```
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
```
|
||||
|
||||
The following RBAC `ClusterRoles` represent the `nodeclient`, `selfnodeclient`, and `selfnodeserver` capabilities. Similar roles
|
||||
may be automatically created in future releases.
|
||||
|
||||
```yml
|
||||
# A ClusterRole which instructs the CSR approver to approve a user requesting
|
||||
# node client credentials.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-client-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/nodeclient"]
|
||||
verbs: ["create"]
|
||||
---
|
||||
# A ClusterRole which instructs the CSR approver to approve a node renewing its
|
||||
# own client credentials.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-client-renewal-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/selfnodeclient"]
|
||||
verbs: ["create"]
|
||||
---
|
||||
# A ClusterRole which instructs the CSR approver to approve a node requesting a
|
||||
# serving cert matching its client cert.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-server-renewal-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/selfnodeserver"]
|
||||
verbs: ["create"]
|
||||
```
|
||||
|
||||
As of 1.8, equivalent roles to the ones listed above are automatically created as part of the default RBAC roles.
|
||||
For 1.8 clusters admins are recommended to bind tokens to the following roles instead of creating their own:
|
||||
|
||||
* `system:certificates.k8s.io:certificatesigningrequests:nodeclient`
|
||||
- Automatically approve CSRs for client certs bound to this role.
|
||||
* `system:certificates.k8s.io:certificatesigningrequests:selfnodeclient`
|
||||
- Automatically approve CSRs when a client bound to its role renews its own certificate.
|
||||
|
||||
These powers can be granted to credentials, such as bootstrapping tokens. For example, to replicate the behavior
|
||||
provided by the removed auto-approval flag, of approving all CSRs by a single group:
|
||||
|
||||
```
|
||||
# REMOVED: This flag no longer works as of 1.7.
|
||||
--insecure-experimental-approve-all-kubelet-csrs-for-group="system:bootstrappers"
|
||||
```
|
||||
|
||||
An admin would create a `ClusterRoleBinding` targeting that group.
|
||||
|
||||
```yml
|
||||
# Approve all CSRs for the group "system:bootstrappers"
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: auto-approve-csrs-for-group
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:bootstrappers
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: approve-node-client-csr
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
To let a node renew its own credentials, an admin can construct a `ClusterRoleBinding` targeting
|
||||
that node's credentials:
|
||||
|
||||
```yml
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: node1-client-cert-renewal
|
||||
subjects:
|
||||
- kind: User
|
||||
name: system:node:node-1 # Let "node-1" renew its client certificate.
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: approve-node-client-renewal-csr
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
Deleting the binding will prevent the node from renewing its client credentials, effectively
|
||||
removing it from the cluster once its certificate expires.
|
||||
|
||||
## kubelet configuration
|
||||
To request a client certificate from kube-apiserver, the kubelet first needs a path to a kubeconfig file that contains the
|
||||
bootstrap authentication token. You can use `kubectl config set-cluster`, `set-credentials`, and `set-context` to build this kubeconfig. Provide the name `kubelet-bootstrap` to `kubectl config set-credentials` and include `--token=<token-value>` as follows:
|
||||
|
||||
```
|
||||
kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=bootstrap.kubeconfig
|
||||
```
|
||||
|
||||
When starting the kubelet, if the file specified by `--kubeconfig` does not exist, the bootstrap kubeconfig is used to request a client certificate from the API server. On approval of the certificate request and receipt back by the kubelet, a kubeconfig file referencing the generated key and obtained certificate is written to the path specified by `--kubeconfig`. The certificate and key file will be placed in the directory specified by `--cert-dir`.
|
||||
|
||||
**Note:** The following flags are required to enable this bootstrapping when starting the kubelet:
|
||||
|
||||
```
|
||||
--bootstrap-kubeconfig="/path/to/bootstrap/kubeconfig"
|
||||
```
|
||||
|
||||
Additionally, in 1.7 the kubelet implements __alpha__ features for enabling rotation of both its client and/or serving certs.
|
||||
These can be enabled through the respective `RotateKubeletClientCertificate` and `RotateKubeletServerCertificate` feature
|
||||
flags on the kubelet, but may change in backward incompatible ways in future releases.
|
||||
|
||||
```
|
||||
--feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
|
||||
```
|
||||
|
||||
`RotateKubeletClientCertificate` causes the kubelet to rotate its client certificates by creating new CSRs as its existing
|
||||
credentials expire. `RotateKubeletServerCertificate` causes the kubelet to both request a serving certificate after
|
||||
bootstrapping its client credentials and rotate the certificate. The serving cert currently does not request DNS or IP
|
||||
SANs.
|
||||
|
||||
## kubectl approval
|
||||
The signing controller does not immediately sign all certificate requests. Instead, it waits until they have been flagged with an
|
||||
"Approved" status by an appropriately-privileged user. This is intended to eventually be an automated process handled by an external
|
||||
approval controller, but for the alpha version of the API it can be done manually by a cluster administrator using kubectl.
|
||||
An administrator can list CSRs with `kubectl get csr` and describe one in detail with `kubectl describe csr <name>`. Before the 1.6 release there were
|
||||
[no direct approve/deny commands](https://github.com/kubernetes/kubernetes/issues/30163) so an approver had to update
|
||||
the Status field directly ([rough how-to](https://github.com/gtank/csrctl)). Later versions of Kubernetes offer `kubectl certificate approve <name>` and `kubectl certificate deny <name>` commands.
|
||||
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- derekwaynecarr
|
||||
- janetkuo
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: invalid-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: kubernetes-serve-hostname
|
||||
image: k8s.gcr.io/serve_hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "3"
|
||||
memory: 100Mi
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: mylimits
|
||||
spec:
|
||||
limits:
|
||||
- max:
|
||||
cpu: "2"
|
||||
memory: 1Gi
|
||||
min:
|
||||
cpu: 200m
|
||||
memory: 6Mi
|
||||
type: Pod
|
||||
- default:
|
||||
cpu: 300m
|
||||
memory: 200Mi
|
||||
defaultRequest:
|
||||
cpu: 200m
|
||||
memory: 100Mi
|
||||
max:
|
||||
cpu: "2"
|
||||
memory: 1Gi
|
||||
min:
|
||||
cpu: 100m
|
||||
memory: 3Mi
|
||||
type: Container
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: limit-example
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: valid-pod
|
||||
labels:
|
||||
name: valid-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: kubernetes-serve-hostname
|
||||
image: k8s.gcr.io/serve_hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
@@ -0,0 +1,4 @@
|
||||
reviewers:
|
||||
- davidopp
|
||||
- madhusudancs
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: no-annotation
|
||||
labels:
|
||||
name: multischeduler-example
|
||||
spec:
|
||||
containers:
|
||||
- name: pod-with-no-annotation-container
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: annotation-default-scheduler
|
||||
labels:
|
||||
name: multischeduler-example
|
||||
spec:
|
||||
schedulerName: default-scheduler
|
||||
containers:
|
||||
- name: pod-with-default-annotation-container
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: annotation-second-scheduler
|
||||
labels:
|
||||
name: multischeduler-example
|
||||
spec:
|
||||
schedulerName: my-scheduler
|
||||
containers:
|
||||
- name: pod-with-second-annotation-container
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,332 @@
|
||||
---
|
||||
reviewers:
|
||||
- jlowdermilk
|
||||
- justinsb
|
||||
- quinton-hoole
|
||||
title: Running in Multiple Zones
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Kubernetes 1.2 adds support for running a single cluster in multiple failure zones
|
||||
(GCE calls them simply "zones", AWS calls them "availability zones", here we'll refer to them as "zones").
|
||||
This is a lightweight version of a broader Cluster Federation feature (previously referred to by the affectionate
|
||||
nickname ["Ubernetes"](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/multicluster/federation.md)).
|
||||
Full Cluster Federation allows combining separate
|
||||
Kubernetes clusters running in different regions or cloud providers
|
||||
(or on-premises data centers). However, many
|
||||
users simply want to run a more available Kubernetes cluster in multiple zones
|
||||
of their single cloud provider, and this is what the multizone support in 1.2 allows
|
||||
(this previously went by the nickname "Ubernetes Lite").
|
||||
|
||||
Multizone support is deliberately limited: a single Kubernetes cluster can run
|
||||
in multiple zones, but only within the same region (and cloud provider). Only
|
||||
GCE and AWS are currently supported automatically (though it is easy to
|
||||
add similar support for other clouds or even bare metal, by simply arranging
|
||||
for the appropriate labels to be added to nodes and volumes).
|
||||
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Functionality
|
||||
|
||||
When nodes are started, the kubelet automatically adds labels to them with
|
||||
zone information.
|
||||
|
||||
Kubernetes will automatically spread the pods in a replication controller
|
||||
or service across nodes in a single-zone cluster (to reduce the impact of
|
||||
failures.) With multiple-zone clusters, this spreading behavior is
|
||||
extended across zones (to reduce the impact of zone failures.) (This is
|
||||
achieved via `SelectorSpreadPriority`). This is a best-effort
|
||||
placement, and so if the zones in your cluster are heterogeneous
|
||||
(e.g. different numbers of nodes, different types of nodes, or
|
||||
different pod resource requirements), this might prevent perfectly
|
||||
even spreading of your pods across zones. If desired, you can use
|
||||
homogeneous zones (same number and types of nodes) to reduce the
|
||||
probability of unequal spreading.
|
||||
|
||||
When persistent volumes are created, the `PersistentVolumeLabel`
|
||||
admission controller automatically adds zone labels to them. The scheduler (via the
|
||||
`VolumeZonePredicate` predicate) will then ensure that pods that claim a
|
||||
given volume are only placed into the same zone as that volume, as volumes
|
||||
cannot be attached across zones.
|
||||
|
||||
## Limitations
|
||||
|
||||
There are some important limitations of the multizone support:
|
||||
|
||||
* We assume that the different zones are located close to each other in the
|
||||
network, so we don't perform any zone-aware routing. In particular, traffic
|
||||
that goes via services might cross zones (even if pods in some pods backing that service
|
||||
exist in the same zone as the client), and this may incur additional latency and cost.
|
||||
|
||||
* Volume zone-affinity will only work with a `PersistentVolume`, and will not
|
||||
work if you directly specify an EBS volume in the pod spec (for example).
|
||||
|
||||
* Clusters cannot span clouds or regions (this functionality will require full
|
||||
federation support).
|
||||
|
||||
* Although your nodes are in multiple zones, kube-up currently builds
|
||||
a single master node by default. While services are highly
|
||||
available and can tolerate the loss of a zone, the control plane is
|
||||
located in a single zone. Users that want a highly available control
|
||||
plane should follow the [high availability](/docs/admin/high-availability) instructions.
|
||||
|
||||
* StatefulSet volume zone spreading when using dynamic provisioning is currently not compatible with
|
||||
pod affinity or anti-affinity policies.
|
||||
|
||||
* If the name of the StatefulSet contains dashes ("-"), volume zone spreading
|
||||
may not provide a uniform distribution of storage across zones.
|
||||
|
||||
* When specifying multiple PVCs in a Deployment or Pod spec, the StorageClass
|
||||
needs to be configured for a specific, single zone, or the PVs need to be
|
||||
statically provisioned in a specific zone. Another workaround is to use a
|
||||
StatefulSet, which will ensure that all the volumes for a replica are
|
||||
provisioned in the same zone.
|
||||
|
||||
|
||||
## Walkthrough
|
||||
|
||||
We're now going to walk through setting up and using a multi-zone
|
||||
cluster on both GCE & AWS. To do so, you bring up a full cluster
|
||||
(specifying `MULTIZONE=true`), and then you add nodes in additional zones
|
||||
by running `kube-up` again (specifying `KUBE_USE_EXISTING_MASTER=true`).
|
||||
|
||||
### Bringing up your cluster
|
||||
|
||||
Create the cluster as normal, but pass MULTIZONE to tell the cluster to manage multiple zones; creating nodes in us-central1-a.
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-a NUM_NODES=3 bash
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2a NUM_NODES=3 bash
|
||||
```
|
||||
|
||||
This step brings up a cluster as normal, still running in a single zone
|
||||
(but `MULTIZONE=true` has enabled multi-zone capabilities).
|
||||
|
||||
### Nodes are labeled
|
||||
|
||||
View the nodes; you can see that they are labeled with zone information.
|
||||
They are all in `us-central1-a` (GCE) or `us-west-2a` (AWS) so far. The
|
||||
labels are `failure-domain.beta.kubernetes.io/region` for the region,
|
||||
and `failure-domain.beta.kubernetes.io/zone` for the zone:
|
||||
|
||||
```shell
|
||||
> kubectl get nodes --show-labels
|
||||
|
||||
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-master Ready,SchedulingDisabled 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-master
|
||||
kubernetes-minion-87j9 Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-87j9
|
||||
kubernetes-minion-9vlv Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-a12q Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-a12q
|
||||
```
|
||||
|
||||
### Add more nodes in a second zone
|
||||
|
||||
Let's add another set of nodes to the existing cluster, reusing the
|
||||
existing master, running in a different zone (us-central1-b or us-west-2b).
|
||||
We run kube-up again, but by specifying `KUBE_USE_EXISTING_MASTER=true`
|
||||
kube-up will not create a new master, but will reuse one that was previously
|
||||
created instead.
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-b NUM_NODES=3 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
On AWS we also need to specify the network CIDR for the additional
|
||||
subnet, along with the master internal IP address:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2b NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.1.0/24 MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
|
||||
View the nodes again; 3 more nodes should have launched and be tagged
|
||||
in us-central1-b:
|
||||
|
||||
```shell
|
||||
> kubectl get nodes --show-labels
|
||||
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-master Ready,SchedulingDisabled 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-master
|
||||
kubernetes-minion-281d Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-281d
|
||||
kubernetes-minion-87j9 Ready 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-87j9
|
||||
kubernetes-minion-9vlv Ready 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-a12q Ready 17m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-a12q
|
||||
kubernetes-minion-pp2f Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-pp2f
|
||||
kubernetes-minion-wf8i Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-wf8i
|
||||
```
|
||||
|
||||
### Volume affinity
|
||||
|
||||
Create a volume using the dynamic volume creation (only PersistentVolumes are supported for zone affinity):
|
||||
|
||||
```json
|
||||
kubectl create -f - <<EOF
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "claim1",
|
||||
"annotations": {
|
||||
"volume.alpha.kubernetes.io/storage-class": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "5Gi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**NOTE:** For version 1.3+ Kubernetes will distribute dynamic PV claims across
|
||||
the configured zones. For version 1.2, dynamic persistent volumes were
|
||||
always created in the zone of the cluster master
|
||||
(here us-central1-a / us-west-2a); that issue
|
||||
([#23330](https://github.com/kubernetes/kubernetes/issues/23330))
|
||||
was addressed in 1.3+.
|
||||
|
||||
Now lets validate that Kubernetes automatically labeled the zone & region the PV was created in.
|
||||
|
||||
```shell
|
||||
> kubectl get pv --show-labels
|
||||
NAME CAPACITY ACCESSMODES STATUS CLAIM REASON AGE LABELS
|
||||
pv-gce-mj4gm 5Gi RWO Bound default/claim1 46s failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a
|
||||
```
|
||||
|
||||
So now we will create a pod that uses the persistent volume claim.
|
||||
Because GCE PDs / AWS EBS volumes cannot be attached across zones,
|
||||
this means that this pod can only be created in the same zone as the volume:
|
||||
|
||||
```yaml
|
||||
kubectl create -f - <<EOF
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: myfrontend
|
||||
image: nginx
|
||||
volumeMounts:
|
||||
- mountPath: "/var/www/html"
|
||||
name: mypd
|
||||
volumes:
|
||||
- name: mypd
|
||||
persistentVolumeClaim:
|
||||
claimName: claim1
|
||||
EOF
|
||||
```
|
||||
|
||||
Note that the pod was automatically created in the same zone as the volume, as
|
||||
cross-zone attachments are not generally permitted by cloud providers:
|
||||
|
||||
```shell
|
||||
> kubectl describe pod mypod | grep Node
|
||||
Node: kubernetes-minion-9vlv/10.240.0.5
|
||||
> kubectl get node kubernetes-minion-9vlv --show-labels
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-minion-9vlv Ready 22m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
```
|
||||
|
||||
### Pods are spread across zones
|
||||
|
||||
Pods in a replication controller or service are automatically spread
|
||||
across zones. First, let's launch more nodes in a third zone:
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-f NUM_NODES=3 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2c NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.2.0/24 MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
Verify that you now have nodes in 3 zones:
|
||||
|
||||
```shell
|
||||
kubectl get nodes --show-labels
|
||||
```
|
||||
|
||||
Create the guestbook-go example, which includes an RC of size 3, running a simple web app:
|
||||
|
||||
```shell
|
||||
find kubernetes/examples/guestbook-go/ -name '*.json' | xargs -I {} kubectl create -f {}
|
||||
```
|
||||
|
||||
The pods should be spread across all 3 zones:
|
||||
|
||||
```shell
|
||||
> kubectl describe pod -l app=guestbook | grep Node
|
||||
Node: kubernetes-minion-9vlv/10.240.0.5
|
||||
Node: kubernetes-minion-281d/10.240.0.8
|
||||
Node: kubernetes-minion-olsh/10.240.0.11
|
||||
|
||||
> kubectl get node kubernetes-minion-9vlv kubernetes-minion-281d kubernetes-minion-olsh --show-labels
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-minion-9vlv Ready 34m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-281d Ready 20m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-281d
|
||||
kubernetes-minion-olsh Ready 3m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-f,kubernetes.io/hostname=kubernetes-minion-olsh
|
||||
```
|
||||
|
||||
|
||||
Load-balancers span all zones in a cluster; the guestbook-go example
|
||||
includes an example load-balanced service:
|
||||
|
||||
```shell
|
||||
> kubectl describe service guestbook | grep LoadBalancer.Ingress
|
||||
LoadBalancer Ingress: 130.211.126.21
|
||||
|
||||
> ip=130.211.126.21
|
||||
|
||||
> curl -s http://${ip}:3000/env | grep HOSTNAME
|
||||
"HOSTNAME": "guestbook-44sep",
|
||||
|
||||
> (for i in `seq 20`; do curl -s http://${ip}:3000/env | grep HOSTNAME; done) | sort | uniq
|
||||
"HOSTNAME": "guestbook-44sep",
|
||||
"HOSTNAME": "guestbook-hum5n",
|
||||
"HOSTNAME": "guestbook-ppm40",
|
||||
```
|
||||
|
||||
The load balancer correctly targets all the pods, even though they are in multiple zones.
|
||||
|
||||
### Shutting down the cluster
|
||||
|
||||
When you're done, clean up:
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true KUBE_GCE_ZONE=us-central1-f kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true KUBE_GCE_ZONE=us-central1-b kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-a kubernetes/cluster/kube-down.sh
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2c kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2b kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2a kubernetes/cluster/kube-down.sh
|
||||
```
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
reviewers:
|
||||
- Random-Liu
|
||||
title: Validate Node Setup
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Node Conformance Test
|
||||
|
||||
*Node conformance test* is a containerized test framework that provides a system
|
||||
verification and functionality test for a node. The test validates whether the
|
||||
node meets the minimum requirements for Kubernetes; a node that passes the test
|
||||
is qualified to join a Kubernetes cluster.
|
||||
|
||||
## Limitations
|
||||
|
||||
In Kubernetes version 1.5, node conformance test has the following limitations:
|
||||
|
||||
* Node conformance test only supports Docker as the container runtime.
|
||||
|
||||
## Node Prerequisite
|
||||
|
||||
To run node conformance test, a node must satisfy the same prerequisites as a
|
||||
standard Kubernetes node. At a minimum, the node should have the following
|
||||
daemons installed:
|
||||
|
||||
* Container Runtime (Docker)
|
||||
* Kubelet
|
||||
|
||||
## Running Node Conformance Test
|
||||
|
||||
To run the node conformance test, perform the following steps:
|
||||
|
||||
1. Point your Kubelet to localhost `--api-servers="http://localhost:8080"`,
|
||||
because the test framework starts a local master to test Kubelet. There are some
|
||||
other Kubelet flags you may care:
|
||||
* `--pod-cidr`: If you are using `kubenet`, you should specify an arbitrary CIDR
|
||||
to Kubelet, for example `--pod-cidr=10.180.0.0/24`.
|
||||
* `--cloud-provider`: If you are using `--cloud-provider=gce`, you should
|
||||
remove the flag to run the test.
|
||||
|
||||
2. Run the node conformance test with command:
|
||||
|
||||
```shell
|
||||
# $CONFIG_DIR is the pod manifest path of your Kubelet.
|
||||
# $LOG_DIR is the test output path.
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
## Running Node Conformance Test for Other Architectures
|
||||
|
||||
Kubernetes also provides node conformance test docker images for other
|
||||
architectures:
|
||||
|
||||
Arch | Image |
|
||||
--------|:-----------------:|
|
||||
amd64 | node-test-amd64 |
|
||||
arm | node-test-arm |
|
||||
arm64 | node-test-arm64 |
|
||||
|
||||
## Running Selected Test
|
||||
|
||||
To run specific tests, overwrite the environment variable `FOCUS` with the
|
||||
regular expression of tests you want to run.
|
||||
|
||||
```shell
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
-e FOCUS=MirrorPod \ # Only run MirrorPod test
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
To skip specific tests, overwrite the environment variable `SKIP` with the
|
||||
regular expression of tests you want to skip.
|
||||
|
||||
```shell
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
-e SKIP=MirrorPod \ # Run all conformance tests but skip MirrorPod test
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
Node conformance test is a containerized version of [node e2e test](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/devel/e2e-node-tests.md).
|
||||
By default, it runs all conformance tests.
|
||||
|
||||
Theoretically, you can run any node e2e test if you configure the container and
|
||||
mount required volumes properly. But **it is strongly recommended to only run conformance
|
||||
test**, because it requires much more complex configuration to run non-conformance test.
|
||||
|
||||
## Caveats
|
||||
|
||||
* The test leaves some docker images on the node, including the node conformance
|
||||
test image and images of containers used in the functionality
|
||||
test.
|
||||
* The test leaves dead containers on the node. These containers are created
|
||||
during the functionality test.
|
||||
@@ -0,0 +1,3 @@
|
||||
reviewers:
|
||||
- derekwaynecarr
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: best-effort
|
||||
spec:
|
||||
hard:
|
||||
pods: "10"
|
||||
scopes:
|
||||
- BestEffort
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: compute-resources
|
||||
spec:
|
||||
hard:
|
||||
pods: "4"
|
||||
requests.cpu: "1"
|
||||
requests.memory: 1Gi
|
||||
limits.cpu: "2"
|
||||
limits.memory: 2Gi
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: limits
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
defaultRequest:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
type: Container
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: quota-example
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: not-best-effort
|
||||
spec:
|
||||
hard:
|
||||
pods: "4"
|
||||
requests.cpu: "1"
|
||||
requests.memory: 1Gi
|
||||
limits.cpu: "2"
|
||||
limits.memory: 2Gi
|
||||
scopes:
|
||||
- NotBestEffort
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: object-counts
|
||||
spec:
|
||||
hard:
|
||||
persistentvolumeclaims: "2"
|
||||
services.loadbalancers: "2"
|
||||
services.nodeports: "0"
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
title: Configuring Kubernetes with Salt
|
||||
---
|
||||
|
||||
The Kubernetes cluster can be configured using Salt.
|
||||
|
||||
The Salt scripts are shared across multiple hosting providers and depending on where you host your Kubernetes cluster, you may be using different operating systems and different networking configurations. As a result, it's important to understand some background information before making Salt changes in order to minimize introducing failures for other hosting providers.
|
||||
|
||||
## Salt cluster setup
|
||||
|
||||
The **salt-master** service runs on the kubernetes-master [(except on the default GCE and OpenStack-Heat setup)](#standalone-salt-configuration-on-gce-and-others).
|
||||
|
||||
The **salt-minion** service runs on the kubernetes-master and each kubernetes-node in the cluster.
|
||||
|
||||
Each salt-minion service is configured to interact with the **salt-master** service hosted on the kubernetes-master via the **master.conf** file [(except on GCE and OpenStack-Heat)](#standalone-salt-configuration-on-gce-and-others).
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/master.conf
|
||||
master: kubernetes-master
|
||||
```
|
||||
|
||||
The salt-master is contacted by each salt-minion and depending upon the machine information presented, the salt-master will provision the machine as either a kubernetes-master or kubernetes-node with all the required capabilities needed to run Kubernetes.
|
||||
|
||||
If you are running the Vagrant based environment, the **salt-api** service is running on the kubernetes-master. It is configured to enable the vagrant user to introspect the salt cluster in order to find out about machines in the Vagrant environment via a REST API.
|
||||
|
||||
## Standalone Salt Configuration on GCE and others
|
||||
|
||||
On GCE and OpenStack, using the Openstack-Heat provider, the master and nodes are all configured as [standalone minions](http://docs.saltstack.com/en/latest/topics/tutorials/standalone_minion.html). The configuration for each VM is derived from the VM's [instance metadata](https://cloud.google.com/compute/docs/metadata) and then stored in Salt grains (`/etc/salt/minion.d/grains.conf`) and pillars (`/srv/salt-overlay/pillar/cluster-params.sls`) that local Salt uses to enforce state.
|
||||
|
||||
All remaining sections that refer to master/minion setups should be ignored for GCE and OpenStack. One fallout of this setup is that the Salt mine doesn't exist - there is no sharing of configuration amongst nodes.
|
||||
|
||||
## Salt security
|
||||
|
||||
*(Not applicable on default GCE and OpenStack-Heat setup.)*
|
||||
|
||||
Security is not enabled on the salt-master, and the salt-master is configured to auto-accept incoming requests from minions. It is not recommended to use this security configuration in production environments without deeper study. (In some environments this isn't as bad as it might sound if the salt master port isn't externally accessible and you trust everyone on your network.)
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/master.d/auto-accept.conf
|
||||
open_mode: True
|
||||
auto_accept: True
|
||||
```
|
||||
|
||||
## Salt minion configuration
|
||||
|
||||
Each minion in the salt cluster has an associated configuration that instructs the salt-master how to provision the required resources on the machine.
|
||||
|
||||
An example file is presented below using the Vagrant based environment.
|
||||
|
||||
```shell
|
||||
[root@kubernetes-master] $ cat /etc/salt/minion.d/grains.conf
|
||||
grains:
|
||||
etcd_servers: $MASTER_IP
|
||||
cloud: vagrant
|
||||
roles:
|
||||
- kubernetes-master
|
||||
```
|
||||
|
||||
Each hosting environment has a slightly different grains.conf file that is used to build conditional logic where required in the Salt files.
|
||||
|
||||
The following enumerates the set of defined key/value pairs that are supported today. If you add new ones, please make sure to update this list.
|
||||
|
||||
Key | Value
|
||||
-----------------------------------|----------------------------------------------------------------
|
||||
`api_servers` | (Optional) The IP address / host name where a kubelet can get read-only access to kube-apiserver
|
||||
`cbr-cidr` | (Optional) The minion IP address range used for the docker container bridge.
|
||||
`cloud` | (Optional) Which IaaS platform is used to host Kubernetes, *gce*, *azure*, *aws*, *vagrant*
|
||||
`etcd_servers` | (Optional) Comma-delimited list of IP addresses the kube-apiserver and kubelet use to reach etcd. Uses the IP of the first machine in the kubernetes_master role, or 127.0.0.1 on GCE.
|
||||
`hostnamef` | (Optional) The full host name of the machine, i.e. uname -n
|
||||
`node_ip` | (Optional) The IP address to use to address this node
|
||||
`hostname_override` | (Optional) Mapped to the kubelet hostname-override
|
||||
`network_mode` | (Optional) Networking model to use among nodes: *openvswitch*
|
||||
`networkInterfaceName` | (Optional) Networking interface to use to bind addresses, default value *eth0*
|
||||
`publicAddressOverride` | (Optional) The IP address the kube-apiserver should use to bind against for external read-only access
|
||||
`roles` | (Required) 1. `kubernetes-master` means this machine is the master in the Kubernetes cluster. 2. `kubernetes-pool` means this machine is a kubernetes-node. Depending on the role, the Salt scripts will provision different resources on the machine.
|
||||
|
||||
These keys may be leveraged by the Salt sls files to branch behavior.
|
||||
|
||||
In addition, a cluster may be running a Debian based operating system or Red Hat based operating system (Centos, Fedora, RHEL, etc.). As a result, it's important to sometimes distinguish behavior based on operating system using if branches like the following.
|
||||
|
||||
```liquid
|
||||
|
||||
{% if grains['os_family'] == 'RedHat' %}
|
||||
// something specific to a RedHat environment (Centos, Fedora, RHEL) where you may use yum, systemd, etc.
|
||||
{% else %}
|
||||
// something specific to Debian environment (apt-get, initd)
|
||||
{% endif %}
|
||||
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
When configuring default arguments for processes, it's best to avoid the use of EnvironmentFiles (Systemd in Red Hat environments) or init.d files (Debian distributions) to hold default values that should be common across operating system environments. This helps keep our Salt template files easy to understand for editors who may not be familiar with the particulars of each distribution.
|
||||
|
||||
## Future enhancements (Networking)
|
||||
|
||||
Per pod IP configuration is provider-specific, so when making networking changes, it's important to sandbox these as all providers may not use the same mechanisms (iptables, openvswitch, etc.)
|
||||
|
||||
We should define a grains.conf key that captures more specifically what network configuration environment is being used to avoid future confusion across providers.
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
- davidopp
|
||||
- lavalamp
|
||||
- liggitt
|
||||
title: Managing Service Accounts
|
||||
---
|
||||
|
||||
*This is a Cluster Administrator guide to service accounts. It assumes knowledge of
|
||||
the [User Guide to Service Accounts](/docs/user-guide/service-accounts).*
|
||||
|
||||
*Support for authorization and user accounts is planned but incomplete. Sometimes
|
||||
incomplete features are referred to in order to better describe service accounts.*
|
||||
|
||||
## User accounts vs service accounts
|
||||
|
||||
Kubernetes distinguishes between the concept of a user account and a service account
|
||||
for a number of reasons:
|
||||
|
||||
- User accounts are for humans. Service accounts are for processes, which
|
||||
run in pods.
|
||||
- User accounts are intended to be global. Names must be unique across all
|
||||
namespaces of a cluster, future user resource will not be namespaced.
|
||||
Service accounts are namespaced.
|
||||
- Typically, a cluster's User accounts might be synced from a corporate
|
||||
database, where new user account creation requires special privileges and
|
||||
is tied to complex business processes. Service account creation is intended
|
||||
to be more lightweight, allowing cluster users to create service accounts for
|
||||
specific tasks (i.e. principle of least privilege).
|
||||
- Auditing considerations for humans and service accounts may differ.
|
||||
- A config bundle for a complex system may include definition of various service
|
||||
accounts for components of that system. Because service accounts can be created
|
||||
ad-hoc and have namespaced names, such config is portable.
|
||||
|
||||
## Service account automation
|
||||
|
||||
Three separate components cooperate to implement the automation around service accounts:
|
||||
|
||||
- A Service account admission controller
|
||||
- A Token controller
|
||||
- A Service account controller
|
||||
|
||||
### Service Account Admission Controller
|
||||
|
||||
The modification of pods is implemented via a plugin
|
||||
called an [Admission Controller](/docs/admin/admission-controllers). It is part of the apiserver.
|
||||
It acts synchronously to modify pods as they are created or updated. When this plugin is active
|
||||
(and it is by default on most distributions), then it does the following when a pod is created or modified:
|
||||
|
||||
1. If the pod does not have a `ServiceAccount` set, it sets the `ServiceAccount` to `default`.
|
||||
2. It ensures that the `ServiceAccount` referenced by the pod exists, and otherwise rejects it.
|
||||
4. If the pod does not contain any `ImagePullSecrets`, then `ImagePullSecrets` of the
|
||||
`ServiceAccount` are added to the pod.
|
||||
5. It adds a `volume` to the pod which contains a token for API access.
|
||||
6. It adds a `volumeSource` to each container of the pod mounted at `/var/run/secrets/kubernetes.io/serviceaccount`.
|
||||
|
||||
### Token Controller
|
||||
|
||||
TokenController runs as part of controller-manager. It acts asynchronously. It:
|
||||
|
||||
- observes serviceAccount creation and creates a corresponding Secret to allow API access.
|
||||
- observes serviceAccount deletion and deletes all corresponding ServiceAccountToken Secrets.
|
||||
- observes secret addition, and ensures the referenced ServiceAccount exists, and adds a token to the secret if needed.
|
||||
- observes secret deletion and removes a reference from the corresponding ServiceAccount if needed.
|
||||
|
||||
You must pass a service account private key file to the token controller in the controller-manager by using
|
||||
the `--service-account-private-key-file` option. The private key will be used to sign generated service account tokens.
|
||||
Similarly, you must pass the corresponding public key to the kube-apiserver using the `--service-account-key-file`
|
||||
option. The public key will be used to verify the tokens during authentication.
|
||||
|
||||
#### To create additional API tokens
|
||||
|
||||
A controller loop ensures a secret with an API token exists for each service
|
||||
account. To create additional API tokens for a service account, create a secret
|
||||
of type `ServiceAccountToken` with an annotation referencing the service
|
||||
account, and the controller will update it with a generated token:
|
||||
|
||||
secret.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Secret",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "mysecretname",
|
||||
"annotations": {
|
||||
"kubernetes.io/service-account.name": "myserviceaccount"
|
||||
}
|
||||
},
|
||||
"type": "kubernetes.io/service-account-token"
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl create -f ./secret.json
|
||||
kubectl describe secret mysecretname
|
||||
```
|
||||
|
||||
#### To delete/invalidate a service account token
|
||||
|
||||
```shell
|
||||
kubectl delete secret mysecretname
|
||||
```
|
||||
|
||||
### Service Account Controller
|
||||
|
||||
Service Account Controller manages ServiceAccount inside namespaces, and ensures
|
||||
a ServiceAccount named "default" exists in every active namespace.
|
||||
Reference in New Issue
Block a user