Cannot get resource "ingressroutes" in API group "traefik.containo.us" in the namespace "traefik" (Gitlab + K3s)

Hey all,

I made this post on the Gitlab forum, but didn't receive any response. I was wondering if anyone would have any thoughts on this.

Gut feeling

Do you think it has something to do with the Gitlab service account defined in gitlab-admin-service-account.yaml? (see below)

:thinking: Issue description

I am getting the error below when I attempt to have my alpha.test container deployed via Gitlab on my K3s cluster.

Error I’m getting:
This appears in the Job logs:

Error from server (Forbidden): error when retrieving current configuration of:
Resource: "traefik.containo.us/v1alpha1, Resource=ingressroutes", GroupVersionKind: "traefik.containo.us/v1alpha1, Kind=IngressRoute"
Name: "alpha-whoami", Namespace: "traefik"
from server for: "deployment.yml": ingressroutes.traefik.containo.us "alpha-whoami" is forbidden: User "system:serviceaccount:alpha-test-8-production:alpha-test-8-production-service-account" cannot get resource "ingressroutes" in API group "traefik.containo.us" in the namespace "traefik"

:earth_americas: Environment

Version info

  • Gitlab Version: 13.8.3 (self-managed)
  • Gitlab Runner: 13.8.0
  • K3s Version: 1.19.7

:man_dancing: Steps to reproduce the issue

  1. Provision brand new cluster
  2. Connect Gitlab to cluster
  3. Run deployment

:pray: What is expected?

I would like my alpha.test container to deploy in its own namespace, but accept web traffic via the Ingress Controller in the traefik namespace.

:triumph: Steps I have taken already to try and fix

  • Hardcode the namespace into the default namespace (Gitlab kept wanting to do its own project namespace)
  • Delete the service account and re-add it
  • Delete the cluster and re-add it (following these docs)

:sparkles: Additional details

Gitlab service account

I made sure I followed these steps and created the Gitlab service account with this:
Gitlab Service Account settings:

gitlab-admin-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: gitlab-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: gitlab
    namespace: kube-system

How I installed Traefik:

I use Ansible to deploy Traefik via Helm:

ansible-playbook.yaml
---
- name: Add Traefik's chart repository.
  community.kubernetes.helm_repository:
    name: traefik
    repo_url: "https://helm.traefik.io/traefik"

- name: Install Traefik with Helm.
  community.kubernetes.helm:
    name: traefik
    chart_ref: traefik/traefik
    update_repo_cache: yes
    release_namespace: traefik
    create_namespace: yes
    values: "{{ lookup('template', 'traefik-chart-values.yaml') | from_yaml }}"

It calls this values file:

traefik-chart-values.yaml
#
# Advanced K8s settings
#
rbac:
  enabled: true
tolerations:
  - key: "CriticalAddonsOnly"
    operator: "Exists"
  - key: "node-role.kubernetes.io/master"
    operator: "Exists"
    effect: "NoSchedule"

#
# Configure providers
#
providers:
  kubernetesIngress:
    publishedService:
      enabled: true
#
# Create an IngressRoute for the dashboard
#
ingressRoute:
  dashboard:
    enabled: true

# Configure ports
ports:
  # The name of this one can't be changed as it is used for the readiness and
  # liveness probes, but you can adjust its config to your liking
  traefik:
    port: 9000
    # Use hostPort if set.
    # hostPort: 9000
    #
    # Use hostIP if set. If not set, Kubernetes will default to 0.0.0.0, which
    # means it's listening on all your interfaces and all your IPs. You may want
    # to set this value if you need traefik to listen on specific interface
    # only.
    # hostIP: 192.168.100.10

    # Defines whether the port is exposed if service.type is LoadBalancer or
    # NodePort.
    #
    # You SHOULD NOT expose the traefik port on production deployments.
    # If you want to access it from outside of your cluster,
    # use `kubectl port-forward` or create a secure ingress
    expose: true
    # The exposed port for this service
    exposedPort: 9000
    # The port protocol (TCP/UDP)
    protocol: TCP
  web:
    port: 8000
    # hostPort: 8000
    expose: true
    exposedPort: 80
    # The port protocol (TCP/UDP)
    protocol: TCP
    # Use nodeport if set. This is useful if you have configured Traefik in a
    # LoadBalancer
    # nodePort: 32080
    # Port Redirections
    # Added in 2.2, you can make permanent redirects via entrypoints.
    # https://docs.traefik.io/routing/entrypoints/#redirection
    # redirectTo: websecure
  websecure:
    port: 8443
    # hostPort: 8443
    expose: true
    exposedPort: 443
    # The port protocol (TCP/UDP)
    protocol: TCP
    # nodePort: 32443
    # Set TLS at the entrypoint
    # https://doc.traefik.io/traefik/routing/entrypoints/#tls
    tls:
      enabled: true
      # this is the name of a TLSOption definition
      options: ""
      certResolver: ""
      domains: []
      # - main: example.com
      #   sans:
      #     - foo.example.com
      #     - bar.example.com

#
# Things that I felt more comfortable setting via the CLI
#
additionalArguments:
  - "--certificatesresolvers.letsencrypt.acme.email=myemail@email.test"
  - "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
  - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
  - "--api.insecure=true"
  - "--accesslog=true"
  - "--log.level=ERROR"

My deployment

.gitlab-ci.yml
services:
  - name: docker:dind
    alias: docker

stages:
  - deploy

deploy to production:
  stage: deploy
  image: 
    name: bitnami/kubectl:latest
    entrypoint: [""]
  script:
    - kubectl apply -f deployment.yml
  environment:
    name: production
deployment.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: alpha-whoami
  labels:
    app: alpha-whoami
    namespace: alpha-test-8-production
spec:
  containers:
    - name: alpha-whoami
      image: containous/whoami:latest
      ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: alpha-whoami
  namespace: alpha-test-8-production
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: alpha-whoami
  type: ClusterIP
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: alpha-whoami
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`alpha.test`)
      kind: Rule
      services:
        - name: alpha-whoami
          port: 80

Thank you for your help!

If there is anything else that you would like to see, just let me know! Thanks!!!

Hello @jaydrogers :wave:

Thanks a lot for sending a detailed description of the issue you experience.

Based on the error message you got I think that it can be related to RBAC configuration in the Kubernetes cluster.

The user (alpha-test-8-production-service-account) that is connecting has no privileges to access Ingressroute resources. That's why you got 403 Forbidden once you try to apply your configuration via GitLab.

I've just performed a quick test and created a new user that has permission to work with the following resources:

  • deployments
  • services
  • IngressRoutes that are specifically related to Traefik Proxy

I think that should be enough to perform deployment (but it can be modified according to GitLab needs). What you are interested in is apiGroups for traefik.containo.us

On those resources, I defined privileges that can be executed by the user such as: create, list, update, patch`,

---

apiVersion: v1
kind: ServiceAccount
metadata:
  name: alpha-sa
  namespace: default

---

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: role-with-privileges-to-deploy
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "create", "list", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "create", "list", "update", "patch"]
  - apiGroups: ["traefik.containo.us"]
    resources: ["ingressroutes"]
    verbs: ["get", "create", "list", "update", "patch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: user-with-privileges
  namespace: default
subjects:
  - kind: ServiceAccount
    name: alpha-sa
    namespace: default
roleRef:
  kind: Role
  name: role-with-privileges-to-deploy
  apiGroup: rbac.authorization.k8s.io

---

Once you apply that config you can test what the user can do in your cluster.

Can the user create IngressRoutes objects?

➜ kubectl auth can-i create ingressroutes -n default --as system:serviceaccount:default:alpha-sa
yes

Can I update, patch, list the already created Ingressroutes resources?

➜ kubectl auth can-i update ingressroutes -n default --as system:serviceaccount:default:alpha-sa
yes
➜ kubectl auth can-i patch ingressroutes -n default --as system:serviceaccount:default:alpha-sa
yes
➜ kubectl auth can-i list ingressroutes -n default --as system:serviceaccount:default:alpha-sa
yes

Can I delete the IngressRoutes resource?

➜ kubectl auth can-i delete ingressroutes -n default --as system:serviceaccount:default:alpha-sa
no

Based on that example you can try to update privileges for a user you are connecting from Gitlbab to your K8S cluster should solve your issue.

Hope that helps!

This is a huge help, thank you!!

My only challenge is the alpha-service-account is created by Gitlab automatically during deployment (see this table).

I might have to play around with how to have Gitlab create the service account with the correct permissions.

If you know of any thoughts, that would be appreciated otherwise I will report back if I find the solution. Thanks! :raised_hands:

Other notes

I believe my issue has something to do with how Gitlab manages the cluster, specifically with their new feature for creating namespaces (Cluster management project | GitLab)

I also make another forum post on Gitlab where other users are having similar issues:

Update 1: Added clarity for the issue specifically with Gitlab

Thanks for keeping us updated, this is very interesting use case and can helpful for other community members :wink:

PS. I am still on it.

1 Like

Here's another update...

I've spent hours going back and forth with this and I think this is where the issue is at:

(I am new to Kubernetes and Gitlab, so please excuse any terminology errors)

Background

  • Traefik creates a CRD called IngressRoute (completely custom to Traefik v2)
  • Gitlab manages your cluster for you and creates service accounts and namespaces

The problem

  • Gitlab automatically creates separate service accounts on each CI deployment (good for security )
  • Gitlab service accounts can access Ingress but NOT IngressRoute

The solution

I need to figure out a way where Gitlab can create these service accounts and give permissions to IngressRoute automatically.

I'm new to Kubernetes, so I made another post on Gitlab's forum. Hopefully someone is available to assist me sharing the solution with the community soon.

UPDATE: I linked to my Gitlab Forum post and Discourse automatically flagged my post as spam. Here is the link:

https://forum.gitlab.com/t/how-do-i-apply-rbac-permissions-to-service-accounts-created-by-gitlab/49432

Why am I motivated to solve this?

  • Repeatable & automated deployments using Gitlab to "Kubernetes + Traefik v2" will be an awesome stack :sunglasses:

Any other thoughts, feel free to chime in. Thanks!

1 Like

Basically speaking you can modify the existing role that is assigned to alpha-service-account and add the appropriate privileges for Ingressroutes resource. You can also create a new role with the privileges and then bind the role with the service account using RoleBinding.

You can list the existing bindings using the command below:

kubectl get role rolebindings.rbac.authorization.k8s.io

and then display the content of the role using the name of the role you got from the previous command. You should received the following output

➜ k describe role deploy-to-staging
Name:         deploy-to-staging
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources               Non-Resource URLs  Resource Names  Verbs
  ---------               -----------------  --------------  -----
  services                []                 []              [get create list update patch]
  deployments.apps        []                 []              [get list update patch]
  deployments.extensions  []                 []              [get list update patch]

However, according to that documentation the user gitlab which Gitlab is using to connect to your cluster has cluster-admin role so it should be able to modify Ingressroutes resources.

Thanks for your feedback @jakubhajek!

You are right, cluster-admin does have the correct permissions.

I think where it gets weird is this new "Cluster Management" approach they are using:

Linking to Gitlab docs is triggering spam, so copy and paste this in your browser:

https://docs.gitlab.com/ee/user/clusters/management_project.html#permissions

I think this is where the issue is sourcing from. Gitlab is creating these service accounts with edit level privileges, but they don't have the capability to manage IngressRoutes.

The trick is since Gitlab is creating the accounts, I have to apply these RoleBindings AFTER they are created by Gitlab (hoping that Gitlab will create the service accounts with the correct permissions/RoleBinding on creation).

I'm happy to report, I found my solution.

Long story short:

  • Use Ingress, not IngressRoute

More detail:

After days of going back and forth, it all came down to changing my deployment to use Ingress instead of IngressRoute.

My old deployment file had:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: alpha-whoami
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`alpha.test`)
      kind: Rule
      services:
        - name: alpha-whoami
          port: 80

I changed this to be:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: ingress-alpha
spec:
  rules:
    - host: alpha.test
      http:
        paths:
          - path: /
            backend:
              serviceName: alpha-whoami
              servicePort: 80

For total clarity, here is my full deployment file that is working:

working-deployment.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: alpha-whoami
  labels:
    app: alpha-whoami
spec:
  containers:
    - name: alpha-whoami
      image: containous/whoami:latest
      ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: alpha-whoami
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: alpha-whoami
  type: ClusterIP
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: ingress-alpha
spec:
  rules:
    - host: alpha.test
      http:
        paths:
          - path: /
            backend:
              serviceName: alpha-whoami
              servicePort: 80

Important notes

Gut feeling why this happened

  • Gitlab is increasing the security of the runners by limiting access to certain Kubernetes functions
  • Runners have limited permissions (they do not run as cluster-admin anymore)
  • Traefik is using an IngressRoute CRD (not exactly sure why, maybe @jakubhajek can explain the difference?)
  • Gitlab is expecting Ingress when they create service accounts and does not have permission to IngressRoute

Using Ingress fixed my issue. I am now able to run automated deployments between Gitlab and my K8s cluster with Traefik :partying_face:

Hope this helps someone else!

1 Like

I am glad that you found the solution and shared it with the community. :slight_smile:

IngressRoute CRD is not a native Kubernetes implementation of Ingress that is an abstraction layer over HTTP providing load balancing, HTTPS/TLS, and name-based virtual host.
Using Ingressroute CRD you can take advantage of many features that are available in Traefik but not exposed in standard Ingress implementation.

The standard Ingress resource is configured through lots of annotations and the engineering team (considering the feedback expressed by the community) developed CRD providing a more flexible approach to create and configure Traefik resources such as:

  • IngressRoute
  • Middleware
  • Traefik Service
  • IngressRoute TCP / UDP
  • TLSOptions
  • TLSStores

Here are a few links to the official documentation:
https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/
https://doc.traefik.io/traefik/providers/kubernetes-crd/

I hope that helps - let us know. Thanks! :wave:

1 Like

Thanks @jakubhajek! I appreciate your help and extra clarification :raised_hands:

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.