github.com/argoproj/argo-cd/v3@v3.2.1/docs/operator-manual/ingress.md (about)

     1  # Ingress Configuration
     2  
     3  Argo CD API server runs both a gRPC server (used by the CLI), as well as a HTTP/HTTPS server (used by the UI).
     4  Both protocols are exposed by the argocd-server service object on the following ports:
     5  
     6  * 443 - gRPC/HTTPS
     7  * 80 - HTTP (redirects to HTTPS)
     8  
     9  There are several ways how Ingress can be configured.
    10  
    11  ## [Ambassador](https://www.getambassador.io/)
    12  
    13  The Ambassador Edge Stack can be used as a Kubernetes ingress controller with [automatic TLS termination](https://www.getambassador.io/docs/latest/topics/running/tls/#host) and routing capabilities for both the CLI and the UI.
    14  
    15  The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md). Given the `argocd` CLI includes the port number in the request `host` header, 2 Mappings are required. 
    16  Note: Disabling TLS in not required if you are using grpc-web
    17  
    18  ### Option 1: Mapping CRD for Host-based Routing
    19  ```yaml
    20  apiVersion: getambassador.io/v2
    21  kind: Mapping
    22  metadata:
    23    name: argocd-server-ui
    24    namespace: argocd
    25  spec:
    26    host: argocd.example.com
    27    prefix: /
    28    service: https://argocd-server:443
    29  ---
    30  apiVersion: getambassador.io/v2
    31  kind: Mapping
    32  metadata:
    33    name: argocd-server-cli
    34    namespace: argocd
    35  spec:
    36    # NOTE: the port must be ignored if you have strip_matching_host_port enabled on envoy
    37    host: argocd.example.com:443
    38    prefix: /
    39    service: argocd-server:80
    40    regex_headers:
    41      Content-Type: "^application/grpc.*$"
    42    grpc: true
    43  ```
    44  
    45  Login with the `argocd` CLI:
    46  
    47  ```shell
    48  argocd login <host>
    49  ```
    50  
    51  ### Option 2: Mapping CRD for Path-based Routing
    52  
    53  The API server must be configured to be available under a non-root path (e.g. `/argo-cd`). Edit the `argocd-server` deployment to add the `--rootpath=/argo-cd` flag to the argocd-server command.
    54  
    55  ```yaml
    56  apiVersion: getambassador.io/v2
    57  kind: Mapping
    58  metadata:
    59    name: argocd-server
    60    namespace: argocd
    61  spec:
    62    prefix: /argo-cd
    63    rewrite: /argo-cd
    64    service: https://argocd-server:443
    65  ```
    66  
    67  Example of `argocd-cmd-params-cm` configmap
    68  ```yaml
    69  apiVersion: v1
    70  kind: ConfigMap
    71  metadata:
    72    name: argocd-cmd-params-cm
    73    namespace: argocd
    74    labels:
    75      app.kubernetes.io/name: argocd-cmd-params-cm
    76      app.kubernetes.io/part-of: argocd
    77  data:
    78    ## Server properties
    79    # Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from / (default "/")
    80    server.basehref: "/argo-cd"
    81    # Used if Argo CD is running behind reverse proxy under subpath different from /
    82    server.rootpath: "/argo-cd"
    83  ```
    84  
    85  Login with the `argocd` CLI using the extra `--grpc-web-root-path` flag for non-root paths.
    86  
    87  ```shell
    88  argocd login <host>:<port> --grpc-web-root-path /argo-cd
    89  ```
    90  
    91  ## [Contour](https://projectcontour.io/)
    92  The Contour ingress controller can terminate TLS ingress traffic at the edge.
    93  
    94  The Argo CD API server should be run with TLS disabled. Edit the `argocd-server` Deployment to add the `--insecure` flag to the argocd-server container command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
    95  
    96  It is also possible to provide an internal-only ingress path and an external-only ingress path by deploying two instances of Contour: one behind a private-subnet LoadBalancer service and one behind a public-subnet LoadBalancer service. The private Contour deployment will pick up Ingresses annotated with `kubernetes.io/ingress.class: contour-internal` and the public Contour deployment will pick up Ingresses annotated with `kubernetes.io/ingress.class: contour-external`.
    97  
    98  This provides the opportunity to deploy the Argo CD UI privately but still allow for SSO callbacks to succeed.
    99  
   100  ### Private Argo CD UI with  Multiple Ingress Objects and BYO Certificate
   101  Since Contour Ingress supports only a single protocol per Ingress object, define three Ingress objects. One for private HTTP/HTTPS, one for private gRPC, and one for public HTTPS SSO callbacks.
   102  
   103  Internal HTTP/HTTPS Ingress:
   104  ```yaml
   105  apiVersion: networking.k8s.io/v1
   106  kind: Ingress
   107  metadata:
   108    name: argocd-server-http
   109    annotations:
   110      kubernetes.io/ingress.class: contour-internal
   111      ingress.kubernetes.io/force-ssl-redirect: "true"
   112  spec:
   113    rules:
   114    - host: internal.path.to.argocd.io
   115      http:
   116        paths:
   117        - path: /
   118          pathType: Prefix
   119          backend:
   120            service:
   121              name: argocd-server
   122              port:
   123                name: http
   124    tls:
   125    - hosts:
   126      - internal.path.to.argocd.io
   127      secretName: your-certificate-name
   128  ```
   129  
   130  Internal gRPC Ingress:
   131  ```yaml
   132  apiVersion: networking.k8s.io/v1
   133  kind: Ingress
   134  metadata:
   135    name: argocd-server-grpc
   136    annotations:
   137      kubernetes.io/ingress.class: contour-internal
   138  spec:
   139    rules:
   140    - host: grpc-internal.path.to.argocd.io
   141      http:
   142        paths:
   143        - path: /
   144          pathType: Prefix
   145          backend:
   146            service:
   147              name: argocd-server
   148              port:
   149                name: https
   150    tls:
   151    - hosts:
   152      - grpc-internal.path.to.argocd.io
   153      secretName: your-certificate-name
   154  ```
   155  
   156  External HTTPS SSO Callback Ingress:
   157  ```yaml
   158  apiVersion: networking.k8s.io/v1
   159  kind: Ingress
   160  metadata:
   161    name: argocd-server-external-callback-http
   162    annotations:
   163      kubernetes.io/ingress.class: contour-external
   164      ingress.kubernetes.io/force-ssl-redirect: "true"
   165  spec:
   166    rules:
   167    - host: external.path.to.argocd.io
   168      http:
   169        paths:
   170        - path: /api/dex/callback
   171          pathType: Prefix
   172          backend:
   173            service:
   174              name: argocd-server
   175              port:
   176                name: http
   177    tls:
   178    - hosts:
   179      - external.path.to.argocd.io
   180      secretName: your-certificate-name
   181  ```
   182  
   183  The argocd-server Service needs to be annotated with `projectcontour.io/upstream-protocol.h2c: "https,443"` to wire up the gRPC protocol proxying.
   184  
   185  The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the
   186  `--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
   187  
   188  Contour httpproxy CRD:
   189  
   190  Using a contour httpproxy CRD allows you to use the same hostname for the GRPC and REST api.
   191  
   192  ```yaml
   193  apiVersion: projectcontour.io/v1
   194  kind: HTTPProxy
   195  metadata:
   196    name: argocd-server
   197    namespace: argocd
   198  spec:
   199    ingressClassName: contour
   200    virtualhost:
   201      fqdn: path.to.argocd.io
   202      tls:
   203        secretName: wildcard-tls
   204    routes:
   205      - conditions:
   206          - prefix: /
   207          - header:
   208              name: Content-Type
   209              contains: application/grpc
   210        services:
   211          - name: argocd-server
   212            port: 80
   213            protocol: h2c # allows for unencrypted http2 connections
   214        timeoutPolicy:
   215          response: 1h
   216          idle: 600s
   217          idleConnection: 600s
   218      - conditions:
   219          - prefix: /
   220        services:
   221          - name: argocd-server
   222            port: 80
   223  ```
   224  
   225  ## [kubernetes/ingress-nginx](https://github.com/kubernetes/ingress-nginx)
   226  
   227  ### Option 1: SSL-Passthrough
   228  
   229  Argo CD serves multiple protocols (gRPC/HTTPS) on the same port (443), this provides a
   230  challenge when attempting to define a single nginx ingress object and rule for the argocd-service,
   231  since the `nginx.ingress.kubernetes.io/backend-protocol` [annotation](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#backend-protocol)
   232  accepts only a single value for the backend protocol (e.g. HTTP, HTTPS, GRPC, GRPCS).
   233  
   234  In order to expose the Argo CD API server with a single ingress rule and hostname, the
   235  `nginx.ingress.kubernetes.io/ssl-passthrough` [annotation](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#ssl-passthrough)
   236  must be used to passthrough TLS connections and terminate TLS at the Argo CD API server.
   237  
   238  ```yaml
   239  apiVersion: networking.k8s.io/v1
   240  kind: Ingress
   241  metadata:
   242    name: argocd-server-ingress
   243    namespace: argocd
   244    annotations:
   245      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
   246      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
   247  spec:
   248    ingressClassName: nginx
   249    rules:
   250    - host: argocd.example.com
   251      http:
   252        paths:
   253        - path: /
   254          pathType: Prefix
   255          backend:
   256            service:
   257              name: argocd-server
   258              port:
   259                name: https
   260  ```
   261  
   262  The above rule terminates TLS at the Argo CD API server, which detects the protocol being used,
   263  and responds appropriately. Note that the `nginx.ingress.kubernetes.io/ssl-passthrough` annotation
   264  requires that the `--enable-ssl-passthrough` flag be added to the command line arguments to
   265  `nginx-ingress-controller`.
   266  
   267  #### SSL-Passthrough with cert-manager and Let's Encrypt
   268  
   269  ```yaml
   270  apiVersion: networking.k8s.io/v1
   271  kind: Ingress
   272  metadata:
   273    name: argocd-server-ingress
   274    namespace: argocd
   275    annotations:
   276      cert-manager.io/cluster-issuer: letsencrypt-prod
   277      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
   278      # If you encounter a redirect loop or are getting a 307 response code
   279      # then you need to force the nginx ingress to connect to the backend using HTTPS.
   280      #
   281      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
   282  spec:
   283    ingressClassName: nginx
   284    rules:
   285    - host: argocd.example.com
   286      http:
   287        paths:
   288        - path: /
   289          pathType: Prefix
   290          backend:
   291            service:
   292              name: argocd-server
   293              port:
   294                name: https
   295    tls:
   296    - hosts:
   297      - argocd.example.com
   298      secretName: argocd-server-tls # as expected by argocd-server
   299  ```
   300  
   301  ### Option 2: SSL Termination at Ingress Controller
   302  
   303  An alternative approach is to perform the SSL termination at the Ingress. Since an `ingress-nginx` Ingress supports only a single protocol per Ingress object, two Ingress objects need to be defined using the `nginx.ingress.kubernetes.io/backend-protocol` annotation, one for HTTP/HTTPS and the other for gRPC.
   304  
   305  Each ingress will be for a different domain (`argocd.example.com` and `grpc.argocd.example.com`). This requires that the Ingress resources use different TLS `secretName`s to avoid unexpected behavior.
   306  
   307  HTTP/HTTPS Ingress:
   308  ```yaml
   309  apiVersion: networking.k8s.io/v1
   310  kind: Ingress
   311  metadata:
   312    name: argocd-server-http-ingress
   313    namespace: argocd
   314    annotations:
   315      nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
   316      nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
   317  spec:
   318    ingressClassName: nginx
   319    rules:
   320    - http:
   321        paths:
   322        - path: /
   323          pathType: Prefix
   324          backend:
   325            service:
   326              name: argocd-server
   327              port:
   328                name: http
   329      host: argocd.example.com
   330    tls:
   331    - hosts:
   332      - argocd.example.com
   333      secretName: argocd-ingress-http
   334  ```
   335  
   336  gRPC Ingress:
   337  ```yaml
   338  apiVersion: networking.k8s.io/v1
   339  kind: Ingress
   340  metadata:
   341    name: argocd-server-grpc-ingress
   342    namespace: argocd
   343    annotations:
   344      nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
   345  spec:
   346    ingressClassName: nginx
   347    rules:
   348    - http:
   349        paths:
   350        - path: /
   351          pathType: Prefix
   352          backend:
   353            service:
   354              name: argocd-server
   355              port:
   356                name: https
   357      host: grpc.argocd.example.com
   358    tls:
   359    - hosts:
   360      - grpc.argocd.example.com
   361      secretName: argocd-ingress-grpc
   362  ```
   363  
   364  The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the
   365  `--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
   366  
   367  The obvious disadvantage to this approach is that this technique requires two separate hostnames for
   368  the API server -- one for gRPC and the other for HTTP/HTTPS. However it allows TLS termination to
   369  happen at the ingress controller.
   370  
   371  
   372  ## [Traefik (v3.0)](https://docs.traefik.io/)
   373  
   374  Traefik can be used as an edge router and provide [TLS](https://docs.traefik.io/user-guides/grpc/) termination within the same deployment.
   375  
   376  It currently has an advantage over NGINX in that it can terminate both TCP and HTTP connections _on the same port_ meaning you do not require multiple hosts or paths.
   377  
   378  The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command or set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
   379  
   380  ### IngressRoute CRD
   381  ```yaml
   382  apiVersion: traefik.io/v1alpha1
   383  kind: IngressRoute
   384  metadata:
   385    name: argocd-server
   386    namespace: argocd
   387  spec:
   388    entryPoints:
   389      - websecure
   390    routes:
   391      - kind: Rule
   392        match: Host(`argocd.example.com`)
   393        priority: 10
   394        services:
   395          - name: argocd-server
   396            port: 80
   397      - kind: Rule
   398        match: Host(`argocd.example.com`) && Header(`Content-Type`, `application/grpc`)
   399        priority: 11
   400        services:
   401          - name: argocd-server
   402            port: 80
   403            scheme: h2c
   404    tls:
   405      certResolver: default
   406  ```
   407  
   408  ## AWS Application Load Balancers (ALBs) And Classic ELB (HTTP Mode)
   409  AWS ALBs can be used as an L7 Load Balancer for both UI and gRPC traffic, whereas Classic ELBs and NLBs can be used as L4 Load Balancers for both.
   410  
   411  When using an ALB, you'll want to create a second service for argocd-server. This is necessary because we need to tell the ALB to send the GRPC traffic to a different target group than the UI traffic, since the backend protocol is HTTP2 instead of HTTP1.
   412  
   413  ```yaml
   414  apiVersion: v1
   415  kind: Service
   416  metadata:
   417    annotations:
   418      alb.ingress.kubernetes.io/backend-protocol-version: GRPC # This tells AWS to send traffic from the ALB using GRPC. Plain HTTP2 can be used, but the health checks wont be available because argo currently downgrade non-grpc calls to HTTP1
   419    labels:
   420      app: argogrpc
   421    name: argogrpc
   422    namespace: argocd
   423  spec:
   424    ports:
   425    - name: "443"
   426      port: 443
   427      protocol: TCP
   428      targetPort: 8080
   429    selector:
   430      app.kubernetes.io/name: argocd-server
   431    sessionAffinity: None
   432    type: NodePort
   433  ```
   434  
   435  Once we create this service, we can configure the Ingress to conditionally route all `application/grpc` traffic to the new HTTP2 backend, using the `alb.ingress.kubernetes.io/conditions` annotation, as seen below. Note: The value after the . in the condition annotation _must_ be the same name as the service that you want traffic to route to - and will be applied on any path with a matching serviceName.
   436  
   437  Also note that we can configure the health check to return the gRPC health status code `OK - 0` from the argocd-server by setting the health check path to `/grpc.health.v1.Health/Check`. By default, the ALB health check for gRPC returns the status code `UNIMPLEMENTED - 12` on health check path `/AWS.ALB/healthcheck`.
   438  
   439  ```yaml
   440    apiVersion: networking.k8s.io/v1
   441    kind: Ingress
   442    metadata:
   443      annotations:
   444        alb.ingress.kubernetes.io/backend-protocol: HTTPS
   445        # Use this annotation (which must match a service name) to route traffic to HTTP2 backends.
   446        alb.ingress.kubernetes.io/conditions.argogrpc: |
   447          [{"field":"http-header","httpHeaderConfig":{"httpHeaderName": "Content-Type", "values":["application/grpc"]}}]
   448        alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
   449        # Use this annotation to receive OK - 0 instead of UNIMPLEMENTED - 12 for gRPC health check.
   450        alb.ingress.kubernetes.io/healthcheck-path: /grpc.health.v1.Health/Check
   451        alb.ingress.kubernetes.io/success-codes: '0'
   452      name: argocd
   453      namespace: argocd
   454    spec:
   455      rules:
   456      - host: argocd.argoproj.io
   457        http:
   458          paths:
   459          - path: /
   460            backend:
   461              service:
   462                name: argogrpc # The grpc service must be placed before the argocd-server for the listening rules to be created in the correct order
   463                port:
   464                  number: 443
   465            pathType: Prefix
   466          - path: /
   467            backend:
   468              service:
   469                name: argocd-server
   470                port:
   471                  number: 443
   472            pathType: Prefix
   473      tls:
   474      - hosts:
   475        - argocd.argoproj.io
   476  ```
   477  
   478  ## [Istio](https://www.istio.io)
   479  You can put Argo CD behind Istio using following configurations. Here we will achieve both serving Argo CD behind istio and using subpath on Istio
   480  
   481  First we need to make sure that we can run Argo CD with subpath (ie /argocd). For this we have used install.yaml from argocd project as is
   482  
   483  ```bash
   484  curl -kLs -o install.yaml https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
   485  ```
   486  
   487  save following file as kustomization.yml
   488  
   489  ```yaml
   490  apiVersion: kustomize.config.k8s.io/v1beta1
   491  kind: Kustomization
   492  resources:
   493  - ./install.yaml
   494  
   495  patches:
   496  - path: ./patch.yml
   497  ``` 
   498  
   499  And following lines as patch.yml
   500  
   501  ```yaml
   502  # Use --insecure so Ingress can send traffic with HTTP
   503  # --bashref /argocd is the subpath like https://IP/argocd
   504  # env was added because of https://github.com/argoproj/argo-cd/issues/3572 error
   505  ---
   506  apiVersion: apps/v1
   507  kind: Deployment
   508  metadata:
   509   name: argocd-server
   510  spec:
   511   template:
   512     spec:
   513       containers:
   514       - args:
   515         - /usr/local/bin/argocd-server
   516         - --staticassets
   517         - /shared/app
   518         - --redis
   519         - argocd-redis:6379
   520         - --insecure
   521         - --basehref
   522         - /argocd
   523         - --rootpath
   524         - /argocd
   525         name: argocd-server
   526         env:
   527         - name: ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT
   528           value: "0"
   529  ```
   530  
   531  After that install Argo CD  (there should be only 3 yml file defined above in current directory )
   532  
   533  ```bash
   534  kubectl apply -k ./ -n argocd --wait=true
   535  ```
   536  
   537  Be sure you create secret for Istio ( in our case secretname is argocd-server-tls on argocd Namespace). After that we create Istio Resources
   538  
   539  ```yaml
   540  apiVersion: networking.istio.io/v1alpha3
   541  kind: Gateway
   542  metadata:
   543    name: argocd-gateway
   544    namespace: argocd
   545  spec:
   546    selector:
   547      istio: ingressgateway
   548    servers:
   549    - port:
   550        number: 80
   551        name: http
   552        protocol: HTTP
   553      hosts:
   554      - "*"
   555      tls:
   556       httpsRedirect: true
   557    - port:
   558        number: 443
   559        name: https
   560        protocol: HTTPS
   561      hosts:
   562      - "*"
   563      tls:
   564        credentialName: argocd-server-tls
   565        maxProtocolVersion: TLSV1_3
   566        minProtocolVersion: TLSV1_2
   567        mode: SIMPLE
   568        cipherSuites:
   569          - ECDHE-ECDSA-AES128-GCM-SHA256
   570          - ECDHE-RSA-AES128-GCM-SHA256
   571          - ECDHE-ECDSA-AES128-SHA
   572          - AES128-GCM-SHA256
   573          - AES128-SHA
   574          - ECDHE-ECDSA-AES256-GCM-SHA384
   575          - ECDHE-RSA-AES256-GCM-SHA384
   576          - ECDHE-ECDSA-AES256-SHA
   577          - AES256-GCM-SHA384
   578          - AES256-SHA
   579  ---
   580  apiVersion: networking.istio.io/v1alpha3
   581  kind: VirtualService
   582  metadata:
   583    name: argocd-virtualservice
   584    namespace: argocd
   585  spec:
   586    hosts:
   587    - "*"
   588    gateways:
   589    - argocd-gateway
   590    http:
   591    - match:
   592      - uri:
   593          prefix: /argocd
   594      route:
   595      - destination:
   596          host: argocd-server
   597          port:
   598            number: 80
   599  ```
   600  
   601  And now we can browse http://{{ IP }}/argocd (it will be rewritten to https://{{ IP }}/argocd
   602  
   603  
   604  ## Google Cloud load balancers with Kubernetes Ingress
   605  
   606  You can make use of the integration of GKE with Google Cloud to deploy Load Balancers using just Kubernetes objects.
   607  
   608  For this we will need these five objects:
   609  - A Service
   610  - A BackendConfig
   611  - A FrontendConfig
   612  - A secret with your SSL certificate
   613  - An Ingress for GKE
   614  
   615  If you need detail for all the options available for these Google integrations, you can check the [Google docs on configuring Ingress features](https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-features)
   616  
   617  ### Disable internal TLS
   618  
   619  First, to avoid internal redirection loops from HTTP to HTTPS, the API server should be run with TLS disabled.
   620  
   621  Edit the `--insecure` flag in the `argocd-server` command of the argocd-server deployment, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
   622  
   623  ### Creating a service
   624  
   625  Now you need an externally accessible service. This is practically the same as the internal service Argo CD has, but with Google Cloud annotations. Note that this service is annotated to use a [Network Endpoint Group](https://cloud.google.com/load-balancing/docs/negs) (NEG) to allow your load balancer to send traffic directly to your pods without using kube-proxy, so remove the `neg` annotation if that's not what you want.
   626  
   627  The service:
   628  
   629  ```yaml
   630  apiVersion: v1
   631  kind: Service
   632  metadata:
   633    name: argocd-server
   634    namespace: argocd
   635    annotations:
   636      cloud.google.com/neg: '{"ingress": true}'
   637      cloud.google.com/backend-config: '{"ports": {"http":"argocd-backend-config"}}'
   638  spec:
   639    type: ClusterIP
   640    ports:
   641    - name: http
   642      port: 80
   643      protocol: TCP
   644      targetPort: 8080
   645    selector:
   646      app.kubernetes.io/name: argocd-server
   647  ```
   648  
   649  ### Creating a BackendConfig
   650  
   651  See that previous service referencing a backend config called `argocd-backend-config`? So lets deploy it using this yaml:
   652  
   653  ```yaml
   654  apiVersion: cloud.google.com/v1
   655  kind: BackendConfig
   656  metadata:
   657    name: argocd-backend-config
   658    namespace: argocd
   659  spec:
   660    healthCheck:
   661      checkIntervalSec: 30
   662      timeoutSec: 5
   663      healthyThreshold: 1
   664      unhealthyThreshold: 2
   665      type: HTTP
   666      requestPath: /healthz
   667      port: 8080
   668  ```
   669  
   670  It uses the same health check as the pods.
   671  
   672  ### Creating a FrontendConfig
   673  
   674  Now we can deploy a frontend config with an HTTP to HTTPS redirect:
   675  
   676  ```yaml
   677  apiVersion: networking.gke.io/v1beta1
   678  kind: FrontendConfig
   679  metadata:
   680    name: argocd-frontend-config
   681    namespace: argocd
   682  spec:
   683    redirectToHttps:
   684      enabled: true
   685  ```
   686  
   687  ---
   688  !!! note
   689  
   690      The next two steps (the certificate secret and the Ingress) are described supposing that you manage the certificate yourself, and you have the certificate and key files for it. In the case that your certificate is Google-managed, fix the next two steps using the [guide to use a Google-managed SSL certificate](https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs#creating_an_ingress_with_a_google-managed_certificate).
   691  
   692  ---
   693  
   694  ### Creating a certificate secret
   695  
   696  We need now to create a secret with the SSL certificate we want in our load balancer. It's as easy as executing this command on the path you have your certificate keys stored:
   697  
   698  ```
   699  kubectl -n argocd create secret tls secret-yourdomain-com \
   700    --cert cert-file.crt --key key-file.key
   701  ```
   702  
   703  ### Creating an Ingress
   704  
   705  And finally, to top it all, our Ingress. Note the reference to our frontend config, the service, and to the certificate secret.
   706  
   707  ---
   708  !!! note
   709  
   710     GKE clusters running versions earlier than `1.21.3-gke.1600`, [the only supported value for the pathType field](https://cloud.google.com/kubernetes-engine/docs/how-to/load-balance-ingress#creating_an_ingress) is `ImplementationSpecific`. So you must check your GKE cluster's version. You need to use different YAML depending on the version.
   711  
   712  ---
   713  
   714  If you use the version earlier than `1.21.3-gke.1600`, you should use the following Ingress resource:
   715  ```yaml
   716  apiVersion: networking.k8s.io/v1
   717  kind: Ingress
   718  metadata:
   719    name: argocd
   720    namespace: argocd
   721    annotations:
   722      networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config
   723  spec:
   724    tls:
   725      - secretName: secret-example-com
   726    rules:
   727      - host: argocd.example.com
   728        http:
   729          paths:
   730          - pathType: ImplementationSpecific
   731            path: "/*"   # "*" is needed. Without this, the UI Javascript and CSS will not load properly
   732            backend:
   733              service:
   734                name: argocd-server
   735                port:
   736                  number: 80
   737  ```
   738  
   739  If you use the version `1.21.3-gke.1600` or later, you should use the following Ingress resource:
   740  ```yaml
   741  apiVersion: networking.k8s.io/v1
   742  kind: Ingress
   743  metadata:
   744    name: argocd
   745    namespace: argocd
   746    annotations:
   747      networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config
   748  spec:
   749    tls:
   750      - secretName: secret-example-com
   751    rules:
   752      - host: argocd.example.com
   753        http:
   754          paths:
   755          - pathType: Prefix
   756            path: "/"
   757            backend:
   758              service:
   759                name: argocd-server
   760                port:
   761                  number: 80
   762  ```
   763  
   764  As you may know already, it can take some minutes to deploy the load balancer and become ready to accept connections. Once it's ready, get the public IP address for your Load Balancer, go to your DNS server (Google or third party) and point your domain or subdomain (i.e. argocd.example.com) to that IP address.
   765  
   766  You can get that IP address describing the Ingress object like this:
   767  
   768  ```
   769  kubectl -n argocd describe ingresses argocd | grep Address
   770  ```
   771  
   772  Once the DNS change is propagated, you're ready to use Argo with your Google Cloud Load Balancer
   773  
   774  ## Authenticating through multiple layers of authenticating reverse proxies
   775  
   776  Argo CD endpoints may be protected by one or more reverse proxies layers, in that case, you can provide additional headers through the `argocd` CLI `--header` parameter to authenticate through those layers.
   777  
   778  ```shell
   779  $ argocd login <host>:<port> --header 'x-token1:foo' --header 'x-token2:bar' # can be repeated multiple times
   780  $ argocd login <host>:<port> --header 'x-token1:foo,x-token2:bar' # headers can also be comma separated
   781  ```
   782  ## ArgoCD Server and UI Root Path (v1.5.3)
   783  
   784  Argo CD server and UI can be configured to be available under a non-root path (e.g. `/argo-cd`).
   785  To do this, add the `--rootpath` flag into the `argocd-server` deployment command:
   786  
   787  ```yaml
   788  spec:
   789    template:
   790      spec:
   791        name: argocd-server
   792        containers:
   793        - command:
   794          - /argocd-server
   795          - --repo-server
   796          - argocd-repo-server:8081
   797          - --rootpath
   798          - /argo-cd
   799  ```
   800  NOTE: The flag `--rootpath` changes both API Server and UI base URL.
   801  Example nginx.conf:
   802  
   803  ```
   804  worker_processes 1;
   805  
   806  events { worker_connections 1024; }
   807  
   808  http {
   809  
   810      sendfile on;
   811  
   812      server {
   813          listen 443;
   814  
   815          location /argo-cd/ {
   816              proxy_pass         https://localhost:8080/argo-cd/;
   817              proxy_redirect     off;
   818              proxy_set_header   Host $host;
   819              proxy_set_header   X-Real-IP $remote_addr;
   820              proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
   821              proxy_set_header   X-Forwarded-Host $server_name;
   822              # buffering should be disabled for api/v1/stream/applications to support chunked response
   823              proxy_buffering off;
   824          }
   825      }
   826  }
   827  ```
   828  Flag ```--grpc-web-root-path ``` is used to provide a non-root path (e.g. /argo-cd)
   829  
   830  ```shell
   831  $ argocd login <host>:<port> --grpc-web-root-path /argo-cd
   832  ```
   833  
   834  ## UI Base Path
   835  
   836  If the Argo CD UI is available under a non-root path (e.g. `/argo-cd` instead of `/`) then the UI path should be configured in the API server.
   837  To configure the UI path add the `--basehref` flag into the `argocd-server` deployment command:
   838  
   839  ```yaml
   840  spec:
   841    template:
   842      spec:
   843        name: argocd-server
   844        containers:
   845        - command:
   846          - /argocd-server
   847          - --repo-server
   848          - argocd-repo-server:8081
   849          - --basehref
   850          - /argo-cd
   851  ```
   852  
   853  NOTE: The flag `--basehref` only changes the UI base URL. The API server will keep using the `/` path so you need to add a URL rewrite rule to the proxy config.
   854  Example nginx.conf with URL rewrite:
   855  
   856  ```
   857  worker_processes 1;
   858  
   859  events { worker_connections 1024; }
   860  
   861  http {
   862  
   863      sendfile on;
   864  
   865      server {
   866          listen 443;
   867  
   868          location /argo-cd {
   869              rewrite /argo-cd/(.*) /$1  break;
   870              proxy_pass         https://localhost:8080;
   871              proxy_redirect     off;
   872              proxy_set_header   Host $host;
   873              proxy_set_header   X-Real-IP $remote_addr;
   874              proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
   875              proxy_set_header   X-Forwarded-Host $server_name;
   876              # buffering should be disabled for api/v1/stream/applications to support chunked response
   877              proxy_buffering off;
   878          }
   879      }
   880  }
   881  ```