<p>I am trying to create a Pod that is able to create and update a specific configmap using <code>Role.rules.resourceNames</code>. I am able to perform a get request for the resource to the API from within the pod, but I'm not able to create the resource, instead getting</p>
<pre><code>$ kubectl logs rbac-test
Error from server (Forbidden): error when creating &quot;/config/aaa.yaml&quot;: configmaps is forbidden: User &quot;system:serviceaccount:default:rbac-test&quot; cannot create resource &quot;configmaps&quot; in API group &quot;&quot; in the namespace &quot;default&quot;
</code></pre>
<p>If I remove the <code>resourceNames</code> attribute I am able to create the configmap, but I don't necessarily want this pod to be able to create and update configmaps willy-nilly. How can I restrict the serviceAccount's roles so that this pod can manipulate only the named configmap <code>aaa</code>?</p>
EDIT
<p>I got some help in the kubernetes slack (thank you, Alan). RBAC happens at the level of the URL so resourceName-restricted authorization can't happen for create URLs since there is no resource name in the URL!</p>
<pre class="lang-yaml prettyprint-override"><code>kind: Pod
apiVersion: v1
metadata:
  name: rbac-test
spec:
  restartPolicy: Never
  serviceAccountName: rbac-test
  imagePullSecrets:
    - name: docker-hub-creds 
  containers:
    - name: rbac-test
      image: bitnami/kubectl
      command: [ &quot;kubectl&quot; ]
      args: [ &quot;apply&quot;, &quot;-f&quot;, &quot;/config/aaa.yaml&quot; ]
      volumeMounts:
        - name: aaa-config
          mountPath: /config/
  volumes:
    - name: aaa-config
      configMap:
        name: aaa-config

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: aaa-config
data:
  aaa.yaml: |
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: aaa
    data:
      value: na

---
apiVersion: v1     
kind: ServiceAccount
metadata:
  name: rbac-test

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbac-test
rules:
  - apiGroups: [ &quot;&quot; ]
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;create&quot;, &quot;update&quot; ]
    resourceNames: [ &quot;aaa&quot; ]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rbac-test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rbac-test
subjects:
  - kind: ServiceAccount
    name: rbac-test
</code></pre>

littlebenlittle
<p>As mention by Shai Katz in previous answer according to documentation: <a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-resources" rel="noreferrer">Using RBAC Authorization - Referring to resources</a></p>
<blockquote>
<p>You cannot restrict <code>create</code> or <code>deletecollection</code> requests by <code>resourceName</code>. For create, this limitation is because the object name is not known at authorization time.</p>
</blockquote>
<p>Solution provided in the edit section - still will not work.</p>
<pre><code>apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbac-test
rules:
  - apiGroups: [ &quot;&quot; ]
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;create&quot;, &quot;update&quot; ]
    resourceNames: [ &quot;aaa&quot; ]
</code></pre>
<p>This config allows you to only get and update existing configmap named <code>aaa</code> while the create operation is pointless as this resource cannot be created..</p>
<h3>How can I restrict the serviceAccount's roles so that this pod can manipulate only the named configmap</h3>
<p>You can achieve what you want if you will edit your <a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-example" rel="noreferrer">Role</a></p>
<p><strong>Solution 1</strong></p>
<pre><code>apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbac-test
rules:
  - apiGroups: [ &quot;&quot; ]             #this rule will allow to update existing configmap aaa referenced by resourcename 
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;update&quot; ]    
    resourceNames: [ &quot;aaa&quot; ]
  - apiGroups: [ &quot;&quot; ]             #this rule will allow you to create configmaps
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;create&quot; ]   
</code></pre>
<p>It can be verified by executing commands below:</p>
<pre><code>$ kubectl auth can-i update configmaps/aaa --as=system:serviceaccount:default:rbac-test
yes
$ kubectl auth can-i create configmaps/new-aaa --as=system:serviceaccount:default:rbac-test
yes
</code></pre>
<p>However, in this scenario <code>rbac-test pod/sa</code> can perform <code>update</code> action by executing <code>kubectl replace</code> command f.e:</p>
<p><code>$ kubectl replace -f /config/aaa.yaml</code></p>
<p>I you are interested with <code>$ kubectl apply</code> probably you should use verb <code>patch</code> like in the example below.</p>
<pre><code>  - apiGroups: [ &quot;&quot; ]       
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;patch&quot; ]    
    resourceNames: [ &quot;aaa&quot; ]
</code></pre>
<p><strong>Solution 2</strong> - More restrictive approach.</p>
<p>Instead of giving your <code>serviceAccount: rbac-test</code> permission to create configs in k8s api. Please consider creating two configmaps:</p>
<p>a)</p>
<pre><code>$ kubectl create cm aaa ### an empty &quot;aaa&quot; configmap
</code></pre>
<p>b)</p>
<pre><code>kubectl apply -f - &lt;&lt;EOF
kind: ConfigMap
apiVersion: v1
metadata:
  name: aaa-config
data:
  aaa.yaml: |
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: aaa
    data:
      value: na
EOF
</code></pre>
<p>This <code>configmap</code> will be populated to the <code>POD</code> using <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-specific-path-in-the-volume" rel="noreferrer">volumes</a>. <code>Configmap.data</code> will be stored inside the <code>pods</code> directory under <code>/config/aaa.yaml</code></p>
<pre><code>kind: ConfigMap
apiVersion: v1
metadata:
  name: aaa
data:
  value: na
</code></pre>
<p>Configure this <code>RBAC Role</code>:</p>
<pre><code>apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rbac-test
rules:
  - apiGroups: [ &quot;&quot; ]             #this rule will allow to patch existing empty &quot;aaa&quot; configmap aaa referenced by resourcename 
    resources: [ &quot;configmaps&quot; ]
    verbs: [ &quot;get&quot;, &quot;patch&quot; ]    
    resourceNames: [ &quot;aaa&quot; ]
</code></pre>
<p>In this scenario you will have preconfigured <code>aaa</code> empty <code>configmap</code> and your <code>pod</code> with associated <code>rbac-test serviceAccount</code> will be able to perform <code>patch</code> request using provided YAML manifest stored in <code>/config/aaa.yaml</code> inside the <code>Pod</code>.</p>
<pre><code>$ kubectl auth can-i patch configmaps/aaa --as=system:serviceaccount:default:rbac-test
yes
$ kubectl auth can-i create configmaps/new-aaa --as=system:serviceaccount:default:rbac-test
no
</code></pre>
<p>To check which verbs you can use in <code>RBAC</code> for <code>ConfigMap</code> execute:</p>
<pre><code>$ kubectl api-resources -o wide | grep configmap
configmaps                        cm                                          true         ConfigMap                        [create delete deletecollection get list patch update watch]
</code></pre>
