<p>I have a requirement to invoke a Kubernetes job from another pod in the same namespace in a RBAC enabled cluster. The job is created using the C#  <a href="https://github.com/kubernetes-client/csharp" rel="nofollow noreferrer">Kubernetes client library</a>. This task works correctly on a test environment that does not have RBAC enabled.  </p>

<p>After following the <a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/" rel="nofollow noreferrer">Kubernetes documentation</a> for creating a Service Account, I have the following YAML.</p>

<pre><code>apiVersion: v1
kind: ServiceAccount
metadata:
  name: x20-jobs-sp
  namespace: prod
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: prod
  name: x20-jobs-sp-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["batch", "extensions"]
  resources: ["jobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: x20-jobs-sp-rolebinding
  namespace: prod
subjects:
  - kind: ServiceAccount
    # Reference to ServiceAccount kind's `metadata.name`
    name: x20-jobs-sp
    # Reference to ServiceAccount kind's `metadata.namespace`
    namespace: prod
roleRef:
  kind: ClusterRole
  name: x20-jobs-sp-role
  apiGroup: rbac.authorization.k8s.io
</code></pre>

<p>This is the code that invokes the job.</p>

<pre class="lang-cs prettyprint-override"><code>var job = await client.CreateNamespacedJobAsync(new k8s.Models.V1Job
{
    Metadata = new k8s.Models.V1ObjectMeta
    {
        Name = safeName
    },
    Spec = new k8s.Models.V1JobSpec
    {
        Template = new k8s.Models.V1PodTemplateSpec
        {
            Spec = new k8s.Models.V1PodSpec
            {
                Containers = new List&lt;k8s.Models.V1Container&gt;()
                {
                    new k8s.Models.V1Container
                    {
                        Image = $"{_containerRegistry}/{jobName}:{_imageTag}",
                        Args = args.Select(x =&gt; x.ToString()).ToList(),
                        Env = GetDefaultEnvironment(),
                        Name = safeName,
                        ImagePullPolicy = "Always"  
                    }
                },
                ImagePullSecrets = new List&lt;k8s.Models.V1LocalObjectReference&gt;
                {
                    new k8s.Models.V1LocalObjectReference
                    {
                        Name = _containerRegistry
                    }
                },
                RestartPolicy = "OnFailure", 
                ServiceAccountName = "x20-jobs-sp" // jobs service principal
            }
        },
        TtlSecondsAfterFinished = _ttlSecondsAfterFinished
    }
}, _namespace);

</code></pre>

<p>This correctly create's the ServiceAccount, ClusterRole and ClusterRoleBinding, however attempting to invoke the task still result's in a <code>Forbidden</code> result.</p>

<p>I've attempted a number of different options for the ClusterRole including using the built in <code>cluster-admin</code> role, all without success. This has been tested using the <code>kubectl auth can-i</code> command.</p>

<p>What am I missing?</p>

<p>So it turned out that the cause was the default service account for the pod that was attempting to invoke the job didn't have the necessary rolebindings.<br>
I tested this by adding the <code>cluster-admin</code> RoleBinding to the default service account in the namespace and invoking the job.<br>
<code>kubectl create clusterrolebinding --user system:serviceaccount:prod:default prod-cluster-admin --clusterrole cluster-admin</code>  </p>
