<p>I'm using <a href="https://kubernetes.github.io/ingress-nginx/" rel="nofollow noreferrer">ingress-nginx-controller</a> (0.32.0) and am attempting to point an ExternalName service at a URL and yet it’s stuck in a loop of 308 Redirects. I've seen plenty of issues out there and I figure there’s just one thing off with my configuration. Is there something really small that I'm missing here?</p>

<p>ConfigMap for NGINX Configuration:</p>

<pre><code>kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  use-proxy-protocol: "true"
  use-forwarded-headers: "true"
  proxy-real-ip-cidr: "0.0.0.0/0" # restrict this to the IP addresses of ELB
  proxy-read-timeout: "3600"
  proxy-send-timeout: "3600"
  backend-protocol: "HTTPS"
  ssl-redirect: "false"
  http-snippet: |
    map true $pass_access_scheme {
      default "https";
    }
    map true $pass_port {
      default 443;
    }
    server {
      listen 8080 proxy_protocol;
      return 308 https://$host$request_uri;
    }
</code></pre>

<p>NGINX Service:</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "XXX"
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"
    service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600"
    service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: http
</code></pre>

<p>Ingress Definition:</p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-members-portal
  namespace: dev
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - host: foo-111.dev.bar.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: foo-service
          servicePort: 80
</code></pre>

<p>ExternalName Service:</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo.staging.bar.com
selector:
  app: foo
</code></pre>

<p><strong>EDIT</strong></p>

<p>I figured it out! I wanted to point to a service in another namespace, so I changed the ExternalName service to this:</p>

<pre><code>apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo-service.staging.svc.cluster.local
ports:
- port: 80
  protocol: TCP
  targetPort: 80
selector:
  app: foo
</code></pre>

<p>I believe the issue you're seeing is due to the fact that your external service isn't working as you think it is.  In your ingress definition, you are defining the service to utilize port 80 on your <code>foo-service</code>.  In theory, this would redirect you back to your ingress controller's ELB, redirect your request to the <code>https://foo.staging.bar.com</code> address, and move on.</p>

<p>However, external services don't really work that way. Essentially, all <code>externalName</code> will do is run a DNS check with KubeDNS/CoreDNS, and return the CNAME information on that request.  It doesn't handle redirects of any kind.</p>

<p>For example, in this case, <code>foo.staging.bar.com:80</code> would return <code>foo.staging.bar.com:443</code>.  You are directing the request for that site to port <code>80</code>, which in itself directs the request to port <code>8080</code> in the ingress controller, which then redirects that request back out to the ELB's port <code>443</code>.  That redirect logic doesn't coexist with the external service.</p>

<p>The problem here, then, is that your app will essentially then try to do this:</p>

<p><code>http://foo-service:80</code> --> <code>http://foo.staging.bar.com:80/login</code> --> <code>https://foo.staging.bar.com:443</code></p>

<p>My expectation on this is that you never actually reach the third step.  Why? Well because <code>foo-service:80</code> is not directing you to port 443, first of all, but second of all...all <code>coreDNS</code> is doing in the backend is running a DNS check against the <code>foo-service</code>'s external name, which is <code>foo.staging.bar.com</code>.  It's not handling any kind of redirection.  So depending on how your host from your app is returned, and handled, your app may never actually get to that site and port.  So rather than reach that site, you just have your app keep looping back to <code>http://foo-service:80</code> for those requests, which will always result in a 308 loopback.</p>

<p>The key here is that <code>foo-service</code> is the <code>host</code> header being sent to the NGINX Ingress controller, not <code>foo.staging.bar.com</code>.  So on a redirect to <code>443</code>, my expectation is that all that is happening, then, is you are hitting <code>foo-service</code>, and any redirects are being improperly sent back to <code>foo-service:80</code>. </p>

<p>A good way to test this is to run <code>curl -L -v http://foo-service:80</code> and see what happens.  That will follow all redirects from that service, and provide you context as to how your ingress controller is handling those requests.</p>

<p>It's really hard to give more information, as I don't have access to your setup directly.  However, if you know that your app is always going to be hitting port <code>443</code>, it would probably be a good fix, in this case, to change your ingress and service to look something like this:</p>

<pre><code>
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-members-portal
  namespace: dev
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  rules:
  - host: foo-111.dev.bar.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: foo-service
          servicePort: 443
---
apiVersion: v1
kind: Service
metadata:
  name: foo-service
spec:
  type: ExternalName
  externalName: foo.staging.bar.com
</code></pre>

<p>That should ensure you don't have any kind of https redirect.  Unfortunately, this may also cause issues with <code>ssl</code> validation, but that would be another issue all together.  The last piece of I can recommend is to possibly just use <code>foo.staging.bar.com</code> itself, rather than an external service in this case.</p>

<p>For more information, see: <a href="https://kubernetes.io/docs/concepts/services-networking/service/#externalname" rel="nofollow noreferrer">https://kubernetes.io/docs/concepts/services-networking/service/#externalname</a></p>

<p>Hope this helps!</p>
