get vs. list in Kubernetes RBAC - kubernetes

What is the difference between the get and list RBAC verbs?
All I could find in the the documentation is this:
"get (for individual resources), list (for collections, including full object content)", which I find severely lacking. Is list a superset of get, meaning if you have list permissions can you fetch all the information from get and more? While we're at it, what about watch? Does it only give permissions to read the change stream but not full object?

In practice, you can get all of the information you'd normally get out of get calls through list calls. However, having permission to list a resource doesn't mean get calls will work. You still have to use list calls and extract the information that way.
watch is a special verb that gives you permission to see updates on resources in real time. Having watch access without list or get is not very helpful because you won't be able to view the resource after it updates. Through kubectl, I was unable to watch a resource without having the get access to that resource.
To play around with these roles, I'd recommend messing around with roles in a Kubernetes cluster on Katacoda.
Initial setup to make roles and grant them to (fake) users:
kubectl create role deployment-getter --verb=get --resource=deployment
kubectl create role deployment-lister --verb=list --resource=deployment
kubectl create role deployment-watcher --verb=watch --resource=deployment
kubectl create rolebinding only-get --role=deployment-getter --user=only-get
kubectl create rolebinding only-list --role=deployment-lister--user=only-list
kubectl create rolebinding only-watch --role=deployment-watcher--user=only-list
kubectl run nginx --image=nginx # Make a resource to look at
Then you can run kubectl commands as one of the special users to see what limited RBAC permissions look like.
For example, the following commands show that we can only list resources with the list verb.
kubectl get deployment --as list-only # Prints out nginx deployment
kubectl get deployment --as get-only # RBAC error
kubectl get deployment --as watch-only # RBAC error
And this example shows that we can only get resources with the get verb (but you can get similar information by listing resources too).
kubectl get deployment nginx --as get-only -o yaml
# apiVersion: extensions/v1beta1
# kind: Deployment
# ...
kubectl get deployment nginx --as list-only -o yaml # RBAC error
kubectl get deployment --as list-only -o yaml
# apiVersion: v1
# kind: List
# items:
# - apiVersion: extensions/v1beta1
# kind: Deployment
# ...

The get, list, and watch RBAC verbs grant permissions for different Kubernetes API operations.
You can see the corresponding API operations for each object in the Kubernetes API reference, for example, here for the Deployment.
Here are some examples:
get
If you have the get permissions on the Deployment resource, you are allowed to execute the following API request:
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
It returns the manifest of a specific Deployment.
list
If you have the list permission, you are allowed to execute these API requests:
GET /apis/apps/v1/namespaces/{namespace}/deployments
GET /apis/apps/v1/deployments
They both return a list of manifests of Deployments. The former, of all Deployments in a specific namespace, and the latter of all Deployments across all namespaces.
watch
If you have the watch permission, you are allowed to execute these API requests:
GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
GET /apis/apps/v1/watch/deployments [DEPRECATED]
They open a streaming connection that returns you the full manifest of a Deployment whenever it changes (or when a new one is created).
Note that the latter three API endpoints are deprecated, and you should use the endpoints for the list operation with a watch=true parameter instead. However, this still triggers the watch API operation and not list.
Note 1
Commands like kubectl get, kubectl list, etc. just executes these API requests under the hood. For experimentation, you can execute these API requests directly.
For example, first do:
kubectl proxy
And then:
curl localhost:8001/apis/apps/v1/deployments?watch=true
Or, you can also use this (doesn't require kubectl proxy):
kubectl get --raw="/apis/apps/v1/deployments?watch=true"
Note 2
In general, the permission don't imply each other. For example, if you have list permissions, it doesn't mean you can do get or watch requests, and if you have watch permissions, it doesn't mean you can do get or list requests.
Note 3
If you have only watch permissions (but not get and list), you can't watch with kubectl (kubectl get deployment -w) because kubectl makes a get and list request, respectively, before the watch request (to get the resource versions of the watched resources).
More examples in this answer.

Related

How to get another pod name from it's IP?

I have a pod that exposes a port (Server). Other pods (Clients) can communicate with it.
The server can find remote IP and port on a socket (when the client connects to it). I am looking for a way to get the client's pod name (from its IP and port).
I saw a bunch of questions/answers about getting pod names via kubectl. However, I am not sure whether I can do kubectl from within a cluster itself.
I am trying to figure out what is available for something running on the cluster. It's ok if it requires some special privileges. It's more complicated if it requires authentication.
List all the Pods with the List Pods API operation and parse the JSON response for the podIP field (e.g. with jq or some other JSON parsing tool) to find the JSON object of the Pod that has your desired IP address. Then, extract the metadata.name field from this JSON object to get the name of the Pod.
You can do this by either directly using the Kubernetes API (e.g. with curl) or with kubectl (e.g. kubectl get pods -o json | jq ...). In any case, you must include in this request the ServiceAccount token of the ServiceAccount used by the Pod from which you are issuing the request (if you use the Kubernetes API directly, as a Bearer token in the Authorization header, and if you use kubectl with the --token command-line flag).
Regarding authorisation, you need a Role allowing the list verb on the pods resource and a RoleBinding that binds this Role to the ServiceAccount that your Pod is using (by default, Pods use a ServiceAccount named default in their namespace, but you can specify a custom ServiceAccount with the serviceAccountName field of the Pod).
Whatever can be done via kubectl can be done via direct requests to the API server as well. All you need is to have proper ServiceAccount set up for your pod. Once you have it - you use can plenty of libraries dedicated for communication with k8s API server.

A way to communicate to a Pod that it's restarting

I need to communicate to a Pod if it's restarting or not. Because depending of the situation my app is working differently (stateful app). I wouldn't like to create other pod that runs a kind of watchdog and then informs my app if it's restarting or not (after a fault). But maybe there is a way to do it with Kubernetes components (Kubelet,..).
Quoting from Kubernetes Docs:
Processes in containers inside pods can also contact the apiserver.
When they do, they are authenticated as a particular Service Account
(for example, default)
A RoleBinding or ClusterRoleBinding binds a role to subjects. Subjects can be groups, users or ServiceAccounts.
An RBAC Role or ClusterRole contains rules that represent a set of
permissions.
A Role always sets permissions within a particular namespace.
ClusterRole, by contrast, is a non-namespaced resource
So, In-order to get/watch the status of the other pod, you can call Kubernetes API from the pod running your code by using serviceaccounts. Follow below steps in-order to automatically retrieve other pod status from a given pod without any external dependency (Due to reliability concerns, you shouldn't rely upon nodes)
Create a serviceaccount in your pod's (requestor pod) namespace
kubectl create sa pod-reader
If both pods are in same namespace, create role,rolebinding
Create a role
kubectl create role pod-reader --verb=get,watch --resource=pods
Create a rolebinding
kubectl create rolebinding pod-reader-binding --role=pod-reader --serviceaccount=<NAMESPACE>:pod-reader
Else, i.e the pods are in different namespaces, create clusterrole,clusterrolebinding
Create a clusterrole
kubectl create clusterrole pod-reader --verb=get,watch --resource=pods
Create a rolebinding
kubectl create clusterrolebinding pod-reader-binding --clusterrole=pod-reader --serviceaccount=<NAMESPACE>:pod-reader
Verify the permissions
kubectl auth can-i watch pods --as=system:serviceaccount:<NAMESPACE>:pod-reader
Now deploy your pod/(your app) with this serviceaccount.
kubectl create <MY-POD> --image=<MY-CONTAINER-IMAGE> --serviceaccount=pod-reader
This will mount serviceaccount secret token in your pod, which can be found at /var/run/secrets/kubernetes.io/serviceaccount/token. Your app can use this token to make GET requests to Kubernetes API server in-order to get the status of the pod. See below example (this assumes your pod has curl utility installed. However, you can make a relevant API call from your code, pass the Header by reading the serviceaccount token file mounted in your pod).
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl https://kubernetes.default/api/v1/namespaces/<NAMESPACE>/pods/<NAME_OF_THE_OTHER_POD> -H "Authorization: Bearer ${TOKEN}" -k
curl https://kubernetes.default/api/v1/watch/namespaces/<NAMESPACE>/pods/<NAME_OF_THE_OTHER_POD>?timeoutSeconds=30 -H "Authorization: Bearer ${TOKEN}" -k
References:
Kubernetes API
serviceaccount

Get IP addresses of all k8s pods from within a container

I have a service called my-service with an endpoint called refreshCache. my-service is hosted on multiple servers, and occasionally I want an event in my-service on one of the servers to trigger refreshCache on my-service on all servers. To do this I manually maintain a list of all the servers that host my-service, pull that list, and send a REST request to <server>/.../refreshCache for each server.
I'm now migrating my service to k8s. Similarly to before, where I was running refreshCache on all servers that hosted my-service, I now want to be able to run refreshCache on all the pods that host my-service. Unfortunately I cannot manually maintain a list of pod IPs, as my understanding is that IPs are ephemeral in k8s, so I need to be able to dynamically get the IPs of all pods in a node, from within a container in one of those pods. Is this possible?
Note: I'm aware this information is available with kubectl get endpoints ..., however kubectl will not be available within my container.
For achieving this the best way would be to use a K8s config inside the pod.
For this the K8s Client can help. Here is an example python script that can be used to get pods and their metadata from inside the pod.
from kubernetes import client, config
def trigger_refresh_cache():
# it works only if this script is run by K8s as a POD
config.load_incluster_config()
v1 = client.CoreV1Api()
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(label_selector='app=my-service')
for i in ret.items:
print("%s\t%s\t%s" %
(i.status.pod_ip, i.metadata.namespace, i.metadata.name))
# Rest of the logic goes here to trigger endpoint
Here the method load_incluster_config() is used which loads the kubeconfig inside pod via the service account attached to that pod.
You don't need kubectl to access the Kubernetes API. You can do it with any tool that can make HTTP requests.
The Kubernetes API is a simple HTTP REST API, and all the authentication information that you need is present in the container if it runs as a Pod in the cluster.
To get the Endpoints object named my-service from within a container in the cluster, you can do:
curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
https://kubernetes.default.svc:443/api/v1/namespaces/{namespace}/endpoints/my-service
Note: replace {namespace} with the namespace of the my-service Endpoints resource.
And to extract the IP addresses of the returned JSON, you could pipe the output to a tool like jq:
... | jq -r '.subsets[].addresses[].ip'
Note that the Pod from which you are executing this needs read permissions for the Endpoints resource, otherwise the API request is denied.
You can do this with a ClusterRole, ClusterRoleBinding, and Service Account (you need to set this up only once):
kubectl create sa endpoint-reader
kubectl create clusterrole endpoint-reader --verb=get,list --resource=endpoints
kubectl create clusterrolebinding endpoint-reader --serviceaccount=default:endpoint-reader --clusterrole=endpoint-reader
Then, use the endpoint-reader ServiceAccount for the Pod from which you want to execute the above curl command by specifying it in the pod.spec.serviceAccountName field.
Granting permissions for any other API operations (i.e. combinations of verbs and resources) works in the same way.

How to get creator information about particular resource from kubectl get or describe command

I want to know who create pod from kubectl get or describe command.
Can I insert this field into Pod? or Custom Resource Definition?
Please help.
when I access to kubernetes cluster as user 'Alice' and create pod 'sample-pod'
I want to see as follows when exec 'kubectl get pod sample-pod' command.
NAME READY STATUS RESTARTS AGE CREATEUSER
sample-pod 1/1 Running 0 10s Alice
I assume that the information about authenticated Kubernetes users is not included in the general API reference list for Pod core schema objects. Therefore, it's not possible to retrieve user data from Pod specification. Actually, you might try to use Service accounts that granted to manage Kubernetes API via RBAC mechanism, in that way you can create a particular SA in namespace related to a specific user, and use it for any resource Kubernetes creation purpose. Although the information about SA name for specific resource propagated through .spec.serviceAccountName field in relevant object configuration template, you can invoke it using custom-columns= option in kubectl get command:
kubectl get pods -o custom-columns=NAME:.metadata.name,SERVICE_ACCOUNT:.spec.serviceAccountName
kubectl get pods -n -o yaml will give the pod definition. you can edit and use it for deploying pods.

How to restrict default Service account from creating/deleting kubernetes resources

I am using Google cloud's GKE for my kubernetes operations.
I am trying to restrict access to the users that access the clusters using command line. I have applied IAM roles in Google cloud and given view role to the Service accounts and users. It all works fine if we use it through api or "--as " in kubectl commands but when someone tries to do a kubectl create an object without specifying "--as" object still gets created with "default" service account of that particular namespace.
To overcome this problem we gave restricted access to "default" service account but still we were able to create objects.
$ kubectl auth can-i create deploy --as default -n test-rbac
no
$ kubectl run nginx-test-24 -n test-rbac --image=nginx
deployment.apps "nginx-test-24" created
$ kubectl describe rolebinding default-view -n test-rbac
Name: default-view
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: view
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount default test-rbac
I expect users who are accessing cluster through CLI should not be able to create objects if they dont have permisssions, even if they dont use "--as" flag they should be restricted.
Please take in count that first you need to review the prerequisites to use RBAC in GKE
Also, please note that IAM roles applies to the entire Google Cloud project and all clusters within that project and RBAC enables fine grained authorization at a namespace level. So, with GKE these approaches to authorization work in parallel.
For more references, please take a look on this document RBAC in GKE
For all the haters of this question, I wish you could've tried pointing to this:
there is a file at:
~/.config/gcloud/configurations/config_default
in this there is a option under [container] section:
use_application_default_credentials
set to true
Here you go , you learnt something new.. enjoy. Wish you could have tried helping instead of down-voting.