Hi, there I'm devoting myself to implementing the authentication capability in APISIX Ingress Controller, and below is my proposal.
Background Authentication and Authorization are required on the Kubernetes Ingress layer, which is similar to API Gateway. However, due to the lack of some APISIX Consumer alike stuff, APISIX Ingress Controller cannot leverage any Authentication plugins provided by APISIX. That’s why an appropriate way needs to be developed to make up for this drawback. Research The standard Ingress isn’t involve anything about Authentication, thus every Ingress Controllers implement it in different ways. Kong As an API Gateway solution, Kong Ingress Controller implements the KongConsumer CRD, which maps it to the Consumer object in Kong. apiVersion: configuration.konghq.com/v1 kind: KongConsumer metadata: name: <object name> namespace: <object namespace> annotations: kubernetes.io/ingress.class: <controller ingress class, "kong" by default> username: <user name> custom_id: <custom ID> All KongConsumer resources will be watched by Kong Ingress Controller and used when authenticating. Ingress Nginx The Authentication is weak in Ingress Nginx,only basic-auth and digest authentication are supported. It is implemented by specifying annotations in Ingress. nginx.ingress.kubernetes.io/auth-type: [basic|digest] This annotation specifies the authentication type. nginx.ingress.kubernetes.io/auth-secret: secretName And this annotation specifies the Kubernetes Secret name which stores the username and password. apiVersion: v1 data: auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK kind: Secret metadata: name: basic-auth namespace: default type: Opaque --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ingress-with-auth annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth spec: rules: - host: foo.bar.com http: paths: - path: / backend: serviceName: http-svc servicePort: 80 How Consumers Work in APISIX Consumers are always used with Authentication, you need to configure a consumer (with username) and enable several plugins on it, then also enabling these (auth) plugins in the Route. APISIX searches the consumer according to the auth-type and its key (headers or query strings). Frankly, it also works if we just copy this way to APISIX Ingress Controller, but the configure is not so clean and easy. As we first need some kinds of stuff to create the Consumer, then enable (APISIX) plugins on it, and enabling these plugins on ApisixRoute again. We need an easier way. ApisixConsumer ApisixConsumer is necessary as we have to create the consumer. apiVersion: apisix.apache.org/v2alpha1 kind: ApisixConsumer metadata: name: <consumer-name> namespace: <consumer-namespace> labels: group: 111 spec: authParameter: basicAuth: valueRef: # exclusive with value kind: secret name: <secret-name> namespace: <secret-namespace> value: # exclusive with valueRef username: aaa password: xxx keyAuth: key: xxxx # exclusive with keyRef keyRef: # exclusive with key kind: secret name: <secret-name> namespace: <secret-namespace> Currently, only fields under authParameter are concerned (other features like limit-rate, can be put under rateLimiting field and so on), which represents authentications, more auth types can be implemented there, values are kind-dependent, for instance, basic auth needs a username and password configuration in value or importing from a secret (exclusively), in valueRef. All ApisixConsumers will be watched by APISIX Ingress Controller, and corresponding Consumer objects will be created, which name is concatenated by the namespace and name (so it can be unique). All authentication configurations will be translated to the corresponding underlying plugins. You may wonder that why not just using the native plugin way here. This is because the fields above (e.g. password in basic auth) are sensitive and just configuring literally is not so safe, a better way is fetching them from Kubernetes secret, also, the native plugin configuring is too flexible to manage, it might results in some security issues (since validation is not so strong so far). ApisixRoute On the other hand, authentication should be enabled in ApisixRoute, of course, it can be supported by configuring the plugins field: apiVersion: apisix.apache.org/v2alpha1 kind: ApisixRoute metadata: name: test spec: http: - name: rule1 match: paths: - /* backend: serviceName: httpbin servicePort: 8080 plugins: - name: basic-auth enable: true Considering some capabilities like consumer restriction (ACL) and a unifying way for management, native fields will be better here. apiVersion: apisix.apache.org/v2alpha1 kind: ApisixRoute metadata: name: test spec: http: - name: rule1 match: paths: - /* backend: serviceName: httpbin servicePort: 8080 authentication: enable: true type: keyAuth keyAuth: header: Authorization acl: allowedConsumers: selector: group: 111 deniedConsumers: selector: group: 222 rejectedCode: 503 Just enabling the required authentication way in ApisixRoute and configuring the ACL (consumer restriction) on demand. In practice, people won’t configure more than one authentication method in a Route, so here the authentication type must be configured, any extra configurations can be put under another field which name is the same as the authentication type (e.g. configurations for keyAuth is under keyAuth field). As for ACL, Kuberentes typical label-selector is applied as the consumer list might be huge. In this case, it’s not easy to maintain such an ApisixRoute object. All the authentications and ACL will be translated to the underlying APISIX plugins. Thanks! Chao Zhang GitHub: https://github.com/tokers