<p>What's the process for either preventing NGINX from responding to the Public IP, or to get it to redirect to somewhere else - like another URL.</p>
<p>I'm a little stumped as I can't seem to find much in the way of documentation anywhere for this situation. We're using cert-manager too.</p>
<p>Essentially a PEN Test has failed because the public IP is responding with an NGINX/ k8s self-signed cert. We don't want or need that!</p>

<p>It's possible to solve this; easy for HTTP and difficult for HTTPS. The main problem is to issue a certificate for an IP address, not any issuer does that (letsencrypt for example doesn't), so you have to find one or try whichever you use now.</p>
<p>To handle unknown hosts (like an IP address) you can create an ingress object without <code>host</code> field in rules. This will make the created ingress work as 'default' or 'fallback' rule, thus it will be used when there is no better match by <code>Host</code> header (any ingress <em>with</em> <code>host</code> in rules).</p>
<p>To create an ingress object you need a service and here's how you can create a dummy service without endpoints:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: Service
metadata:
  name: dummy-service
spec:
  clusterIP: None
</code></pre>
<p>Next, the ingress for it:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: default-ingress
  annotations:
    kubernetes.io/ingress_class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # Nginx will place this in server block

      # You can redirect all requests somewhere:
      return 301 https://example.com/;
      # or just:
      #return 403;
spec:
  rules:
    # This rule has no 'host' field and because of that
    # NGINX won't include 'server_name' directive in
    # vhost configuration. What this means is that this
    # ingress rule will be used only if the request
    # comes with 'Host' header for which there is no
    # specific rule (IP-address for example).
    - http:
        paths:
          - backend:
              servicePort: 80
              serviceName: dummy-service
</code></pre>
<p>At this point you've got redirect (or 403) working for HTTP and HTTPS, although the latter with a dummy certificate. If you managed to issue a certificate for your IP addresses and save it as a secret, the next thing is to make NGINX to use it instead of its default dummy certificate. For that you need to modify ingress controller deployment by adding <code>--default-ssl-certificate</code> argument:</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
spec:
  template:
    spec:
      containers:
        - name: controller
          args:
            - /nginx-ingress-controller
            # use 'namespace/secret_name' as the value for the argument
            - --default-ssl-certificate=default/ip-cert-secret
</code></pre>
<p>Now NGINX will respond to IP addresses with a valid certificate.</p>
<p><strong>Bonus</strong>: if you have a cert-manager <code>Issuer</code> or <code>ClusterIssuer</code> that can issue a certificate for IP address (like self-signed one), you can request a certificate with the following manifest:</p>
<pre class="lang-yaml prettyprint-override"><code>#apiVersion: cert-manager.io/v1
apiVersion: cert-manager.io/v1beta1
kind: Certificate
metadata:
  name: ip-cert
spec:
  secretName: ip-cert-secret
  duration: 2160h # 90d
  renewBefore: 360h # 15d
  isCA: false
  privateKey:
    algorithm: RSA
    encoding: PKCS1
    size: 2048
  usages:
    - server auth
    - client auth
  commonName: Dummy
  ipAddresses:
  - 10.1.1.13 # fill the list
  issuerRef:
    name: # insert issuer name
    kind: # Issuer or ClusterIssuer 
    group: cert-manager.io
</code></pre>
