Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature req: HTTP -> HTTPS redirects (ALB-native) #487

Closed
danopia opened this issue Jul 26, 2018 · 92 comments
Closed

Feature req: HTTP -> HTTPS redirects (ALB-native) #487

danopia opened this issue Jul 26, 2018 · 92 comments
Labels
kind/feature Categorizes issue or PR as related to a new feature.

Comments

@danopia
Copy link

danopia commented Jul 26, 2018

Right now, in order to redirect users to HTTPS, the application's backend had to serve the redirects since until now ALBs didn't support modifying requests. For comparison, the nginx ingress controller supports HTTP->HTTPS redirects from an annotation because nginx itself will happily redirect.

Today a new ALB feature was launched which lets the ALB itself redirect traffic. This could be used for a few different things, but the obvious primary use-case (and the one called out in the blog post) is HTTP->HTTPS redirects. So hopefully there's a potential clean way for alb-ingress-controller to offer this feature.

Feature announcement, supports redirects and static responses without hitting the backend: https://aws.amazon.com/about-aws/whats-new/2018/07/elastic-load-balancing-announces-support-for-redirects-and-fixed-responses-for-application-load-balancer/

Specific documentation for redirects: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#redirect-actions

@bigkraig bigkraig added the kind/feature Categorizes issue or PR as related to a new feature. label Jul 26, 2018
@whithajess
Copy link

Please someone do this 🎉

@anhpham1509
Copy link

@bigkraig Are you planning to have this in v1.0?

@bigkraig
Copy link

bigkraig commented Aug 1, 2018

How would you all like to see this implemented? The ingress spec is somewhat limiting.

@disha94
Copy link

disha94 commented Aug 1, 2018

Even I am looking for https redirection with alb-ingress.When are you guys planning to implement this feature??

@stevenpall
Copy link

@bigkraig I think it would make sense to have this as another ingress annotation?

@bigkraig
Copy link

bigkraig commented Aug 1, 2018

I think that would be the only way, but I hate to make people make more json encoded annotation strings.

@bigkraig
Copy link

bigkraig commented Aug 1, 2018

The ingress backend spec has serviceName and servicePort.

I'm pretty sure service names can't include a :, so what if we used that to configure the ALB rule actions?

Something like this

paths:
- path: /invalid
  backend:
    serviceName: fixed-response:{"ContentType":"text/plain","StatusCode":503,"MessageBody":"message body"}
- path: /
  backend:
    serviceName: echoserver
    servicePort: 80

@anhpham1509
Copy link

I think it's better to have a boolean annotation and redirect all HTTP requests to HTTPS requests by a listener creation to AWS. What do you think @bigkraig ?

@bigkraig
Copy link

bigkraig commented Aug 1, 2018

The redirect action is much more powerful than that and rather than providing two methods that would conflict, i'd prefer to let users leverage all of the action options in the same method.

@whithajess
Copy link

^ I would agree with @bigkraig it would be good to provide an easy example of the HTTP -> HTTPS config but lets not do two functionality sets, I think that implementation looks good @bigkraig.

@anhpham1509
Copy link

I agree with you about the reusable methods. If you can provide examples then I think it totally works. Anw, I think it's still best to extend the method and utilise what AWS offers.

@gabzim
Copy link

gabzim commented Aug 3, 2018

This is pretty big for us, what's the current workaround you've been using to enforce this?

@anhpham1509
Copy link

At least I'm using https proxy (a nginx app with redirect feature).
However, if we can use AWS ALB feature, it's best.
I tried to create the listener manually but after that, it makes reconcile procedure error as SG has 1 more rule and ALB has 1 more listener.

How do you think if all the state of resources at AWS can be the super-set of what has been configured in the Ingress object?

@bigkraig
Copy link

bigkraig commented Aug 3, 2018

Using the serviceName field won't work, there is some validation that happens.

# * spec.rules[0].http.backend.serviceName: Invalid value: "test:test": a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name',  or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')

@anhpham1509
Copy link

Yeah. I thought about this and it happened with validation.
Is that big to extend the create listener function? @bigkraig

@bigkraig
Copy link

bigkraig commented Aug 7, 2018

the hard part is figuring out a way to configure the actions without making a bunch of complicated annotations. i'll try to find some time to think about it today

@bigkraig
Copy link

bigkraig commented Aug 7, 2018

What does everyone think of this? My only concern here is if the service name my-fixed-response also corresponds to a service in the cluster. In that case I would just default to the annotation.

The idea is that we can define actions using the alb.ingress.kubernetes.io/actions.<action name> annotation and then reference the action in the serviceName. servicePort is unfortunately a required field.

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.my-fixed-response: >-
      {"Type": "fixed-response", "Config": {"ContentType":"text/plain",
      "StatusCode":503, "MessageBody":"message body"}}
spec:
  rules:
    - http:
        paths:
          - path: /503-action-path
            backend:
              serviceName: my-fixed-response
              servicePort: unused

@anhpham1509
Copy link

@bigkraig I think for the type fixed-response, it's good enough. How's about an example for redirect?

@bigkraig
Copy link

bigkraig commented Aug 9, 2018

@anhpham1509 the action looks like:

                    "Type": "redirect",
                    "Order": 1,
                    "RedirectConfig": {
                        "Protocol": "HTTPS",
                        "Port": "44",
                        "Host": "#{host}",
                        "Path": "/#{path}",
                        "Query": "#{query}",
                        "StatusCode": "HTTP_301"
                    }

I think Order is unused, or at least I didn't see a way to configure it in the console. The AWS docs describe protocol://hostname:port/path?query as a config URI, so we could go with the URI or we could go with individual fields. Individual fields would be easier to implement but maybe more complicated to read in an annotation.

alb.ingress.kubernetes.io/actions.my-redirect-via-params: >-
  {"Type": "redirect", "Config": {"Protocol":"HTTPS",
  "Port":"443", "Host":"#{host}", "Path": "/#{path}", "Query": "#{query}", "StatusCode": "HTTP_301"}}
alb.ingress.kubernetes.io/actions.my-redirect-via-uri: >-
  {"Type": "redirect", "Config": {"URI":"https://#{host}:443//#{path}?#{query}", "StatusCode": "HTTP_301"}}

@anhpham1509
Copy link

Yeah. This sounds really good, IMO.
How big is this to be implemented?
I think handling annotations for usage in rule is a bit complicated.

@bigkraig
Copy link

bigkraig commented Aug 9, 2018

It's probably a little more than half a day of work. I'd just need to parse the annotations into a new action type and then replace service backends with those actions, but i'm sure there will be some problems along the way.

@bigkraig
Copy link

bigkraig commented Aug 9, 2018

A bit longer than that, since the default backend stuff would also need it and it has different logic to deal with.

@bigkraig
Copy link

bigkraig commented Aug 9, 2018

Thinking about it, we should also have some kind of way to trigger the annotation usage, incase there are naming conflicts. So use servicePort for that:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.my-fixed-response: >-
      {"Type": "fixed-response", "Config": {"ContentType":"text/plain",
      "StatusCode":503, "MessageBody":"message body"}}
spec:
  rules:
    - http:
        paths:
          - path: /503-action-path
            backend:
              serviceName: my-fixed-response
              servicePort: actions-annotation

@bigkraig
Copy link

bigkraig commented Aug 9, 2018

I'll probably reuse the SDKs types and support all configuration options in https://docs.aws.amazon.com/sdk-for-go/api/service/elbv2/#Action

@anhpham1509
Copy link

Sounds good with the use of servicePort. I’m thinking this would probably takes more than a day. Hope that you have time to implement this soon.

@bigkraig
Copy link

@anhpham1509 I type fast.

If anyone wants to try it out, see #542. Docs are in there and before I give some examples i'd prefer if people read the doc and make sure it is easy to understand, it's probably one of the more complicated annotations.

The only thing left to do in #542 is to add support for the custom actions for the ingresses default backend. I'll probably tackle that next week sometime.

@bdirito
Copy link

bdirito commented Sep 10, 2018

@smaslennikov ah. im not familiar with the intricacies there. do you know for sure such a thing can be done with albs?

@bigkraig
I am seeing the same thing as qgriffith-xylem.

E0910 18:23:32.700816       1 albingress.go:290] splunk/splunk: Failed to reconcile state on this ingress
E0910 18:23:32.700834       1 albingress.go:292] splunk/splunk:  - Failed Listener modification: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
E0910 18:23:32.700839       1 albingress.go:292] splunk/splunk:         status code: 400, request id: 9fa649a8-b526-11e8-8e7d-85cb66be53b8
E0910 18:23:32.700849       1 albingress.go:295] splunk/splunk: Will retry to reconcile in 3m58.910034089s
I0910 18:23:32.701033       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"splunk", Name:"splunk", UID:"a8cc8a2e-a4aa-11e8-9812-06e1fa182b34", APIVersion:"extensions/v1beta1", ResourceVersion:"7277806", FieldPath:""}): type: 'Warning' reason: 'ERROR' Error modifying 443 listener: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
        status code: 400, request id: 9fa649a8-b526-11e8-8e7d-85cb66be53b``
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: splunk
  namespace: splunk
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-abc123...
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/security-groups: albing
    alb.ingress.kubernetes.io/success-codes: 303,200
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80, "HTTPS": 443}]'
    alb.ingress.kubernetes.io/actions.redirect: >-
      {"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS",
      "StatusCode": "HTTP_301"}}
spec:
  rules:
    - http:
        paths:
          - backend:
              serviceName: redirect
              servicePort: use-annotation
    - host: splunk.example.com
      http:
        paths:
          # - backend:
          #     serviceName: redirect
          #     servicePort: use-annotation
          - path:
            backend:
              serviceName: splunkweb
              servicePort: 80
    - host: splunkhec.example.com
      http:
        paths:
          # - backend:
          #     serviceName: redirect
          #     servicePort: use-annotation

          - path:
            backend:
              serviceName: splunkhec
              servicePort: 80

Note that with my slightly different config and use of latest this log does NOT have the null memory dereference error as shown in qgriffith-xylem

@bdirito
Copy link

bdirito commented Sep 10, 2018

@qgriffith-xylem ive found that you can pass in a port to the redirect action. this makes the redirect action work. However it still reports itself as failing in the log and goes into its backoff logic.

    alb.ingress.kubernetes.io/actions.redirect: >-
      {"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS",
      "StatusCode": "HTTP_301", "Port": "443"}}

@qgriffith-xylem
Copy link

@bdirito
Mine if failing to create the 443 listener, it creates the 80 then crashes with the memory issue during the 443 part and does the bit about how it can't create it because it would cause a redirect loop

@a8j8i8t8
Copy link

Same here. I'm getting below with image 487-https-loops.
InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.

@a8j8i8t8
Copy link

a8j8i8t8 commented Sep 11, 2018

Is it possible to re-open this issue?
It's still working neither with latest nor with 487-https-loops . 👎

@bigkraig bigkraig reopened this Sep 11, 2018
@bigkraig
Copy link

I'll try and take a look at this again today. I tested one of the configurations yesterday and I wasn't able to reproduce it.

@a8j8i8t8
Copy link

@bigkraig Please let me know if you need any information, happy to help.

@qgriffith-xylem
Copy link

I saw there was a listener-nil-pointerimage out there and gave it a try. The alb pod no longer crashes however 443 isn't being made

 Warning  ERROR   34s  aws-alb-ingress-controller  Error creating 443 listener: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
           status code: 400, request id: 163a8898-b763-11e8-bccc-8300fb2f0b19

Getting closer

@bigkraig
Copy link

@qgriffith-xylem can you run with --aws-api-debug true and see what that request looks like? I wasn't able to reproduce it on my side with similar ingresses so i'm having a hard time fixing it. That info might help me produce a test case.

@qgriffith-xylem
Copy link

qgriffith-xylem commented Sep 13, 2018

Sure thing, here is the output

0913 16:53:07.483682       1 loadbalancer.go:265] default/sacp-alb: Start ELBV2 creation.
I0913 16:53:07.483993       1 loadbalancer.go:404] Request: elasticloadbalancing/CreateLoadBalancer, Payload: {  IpAddressType: "ipv4",  Name: "3440dd9e-default-sacpalb-bb86",  Scheme: "internet-facing",  SecurityGroups: ["sg-978638e6"],  Subnets: [    "subnet-0f940678",    "subnet-360ab96f",    "subnet-c1ef95fb",    "subnet-c8ae76e3"  ],  Tags: [    {      Key: "Environment",      Value: "dev"    },    {      Key: "Team",      Value: "devops"    },    {      Key: "Note",      Value: "k8s"    },    {      Key: "kubernetes.io/cluster/sa-dev-eks-1",      Value: "owned"    },    {      Key: "kubernetes.io/namespace",      Value: "default"    },    {      Key: "kubernetes.io/ingress-name",      Value: "sacp-alb"    }  ]}
I0913 16:53:08.277061       1 loadbalancer.go:272] default/sacp-alb: Completed ELBV2 creation. Name: 3440dd9e-default-sacpalb-bb86 | ARN: arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c
I0913 16:53:08.277083       1 targetgroup.go:225] default/sacp-alb: Start TargetGroup creation.
I0913 16:53:08.277260       1 targetgroup.go:266] Request: elasticloadbalancing/CreateTargetGroup, Payload: {  HealthCheckIntervalSeconds: 15,  HealthCheckPath: "/login.html",  HealthCheckPort: "traffic-port",  HealthCheckProtocol: "HTTP",  HealthCheckTimeoutSeconds: 5,  HealthyThresholdCount: 2,  Matcher: {    HttpCode: "200"  },  Name: "3440dd9e-e5f5084bacfe6b7d2f3",  Port: 1,  Protocol: "HTTP",  TargetType: "ip",  UnhealthyThresholdCount: 2,  VpcId: "vpc-b6e29ed3"}
I0913 16:53:08.277290       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'CREATE' 3440dd9e-default-sacpalb-bb86 created
I0913 16:53:08.473731       1 elbv2.go:519] Request: elasticloadbalancing/AddTags, Payload: {  ResourceArns: ["arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31"],  Tags: [    {      Key: "Environment",      Value: "dev"    },    {      Key: "Team",      Value: "devops"    },    {      Key: "Note",      Value: "k8s"    },    {      Key: "kubernetes.io/cluster/sa-dev-eks-1",      Value: "owned"    },    {      Key: "kubernetes.io/namespace",      Value: "default"    },    {      Key: "kubernetes.io/ingress-name",      Value: "sacp-alb"    },    {      Key: "kubernetes.io/service-name",      Value: "sacp-war"    },    {      Key: "kubernetes.io/service-port",      Value: "9090"    }  ]}
I0913 16:53:08.545519       1 targetgroup.go:475] Request: elasticloadbalancing/RegisterTargets, Payload: {  TargetGroupArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31",  Targets: [{      Id: "10.32.13.49",      Port: 8080    },{      Id: "10.32.16.220",      Port: 8080    }]}
I0913 16:53:08.875790       1 targetgroup.go:294] Request: elasticloadbalancing/ModifyTargetGroupAttributes, Payload: {  Attributes: [{      Key: "stickiness.enabled",      Value: "true"    },{      Key: "stickiness.lb_cookie.duration_seconds",      Value: "86400"    }],  TargetGroupArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31"}
I0913 16:53:08.912261       1 targetgroup.go:230] default/sacp-alb: Succeeded TargetGroup creation. ARN: arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31 | Name: 3440dd9e-e5f5084bacfe6b7d2f3.
I0913 16:53:08.912285       1 listener.go:197] default/sacp-alb: Start Listener creation.
I0913 16:53:08.912366       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'CREATE' 3440dd9e-e5f5084bacfe6b7d2f3 target group created
I0913 16:53:08.912459       1 listener.go:240] Request: elasticloadbalancing/CreateListener, Payload: {  DefaultActions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  LoadBalancerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c",  Port: 80,  Protocol: "HTTP"}
I0913 16:53:08.948382       1 listener.go:202] default/sacp-alb: Completed Listener creation. ARN: arn:aws:elasticloadbalancing:us-east-1:371066304662:listener/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c/9c2dafd57b153c27 | Port: 80 | Proto: HTTP.
I0913 16:53:08.948401       1 rule.go:143] default/sacp-alb: Start Rule creation.
I0913 16:53:08.948535       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'CREATE' 80 listener created
I0913 16:53:08.948604       1 rule.go:183] Request: elasticloadbalancing/CreateRule, Payload: {  Actions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  Conditions: [{      Field: "host-header",      Values: ["sacp-k8s.dev1-sensus-analytics.com"]    },{      Field: "path-pattern",      Values: ["/"]    }],  ListenerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:listener/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c/9c2dafd57b153c27",  Priority: 1}
I0913 16:53:09.015582       1 rule.go:148] default/sacp-alb: Completed Rule creation. Rule Priority: "1" | Condition: [{    Field: "host-header",    Values: ["sacp-k8s.dev1-sensus-analytics.com"]  },{    Field: "path-pattern",    Values: ["/"]  }]
I0913 16:53:09.015604       1 rule.go:143] default/sacp-alb: Start Rule creation.
I0913 16:53:09.015691       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'CREATE' 1 rule created
I0913 16:53:09.015879       1 rule.go:183] Request: elasticloadbalancing/CreateRule, Payload: {  Actions: [{      TargetGroupArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31",      Type: "forward"    }],  Conditions: [{      Field: "host-header",      Values: ["sacp-k8s.dev1-sensus-analytics.com"]    },{      Field: "path-pattern",      Values: ["/"]    }],  ListenerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:listener/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c/9c2dafd57b153c27",  Priority: 2}
I0913 16:53:09.171619       1 rule.go:148] default/sacp-alb: Completed Rule creation. Rule Priority: "2" | Condition: [{    Field: "host-header",    Values: ["sacp-k8s.dev1-sensus-analytics.com"]  },{    Field: "path-pattern",    Values: ["/"]  }]
I0913 16:53:09.171644       1 listener.go:197] default/sacp-alb: Start Listener creation.
I0913 16:53:09.171836       1 listener.go:240] Request: elasticloadbalancing/CreateListener, Payload: {  Certificates: [{      CertificateArn: "arn:aws:acm:us-east-1:371066304662:certificate/309a6d7a-a4fb-415f-9b4d-718c4c3dda36"    }],  DefaultActions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  LoadBalancerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c",  Port: 443,  Protocol: "HTTPS",  SslPolicy: "ELBSecurityPolicy-2016-08"}
I0913 16:53:09.171874       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'CREATE' 2 rule created
E0913 16:53:09.487418       1 api.go:318] Failed request: elasticloadbalancing/CreateListener, Payload: {  Certificates: [{      CertificateArn: "arn:aws:acm:us-east-1:371066304662:certificate/309a6d7a-a4fb-415f-9b4d-718c4c3dda36"    }],  DefaultActions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  LoadBalancerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c",  Port: 443,  Protocol: "HTTPS",  SslPolicy: "ELBSecurityPolicy-2016-08"}, Error: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
        status code: 400, request id: 7e3c2e88-b775-11e8-9b2f-df73d947993a
E0913 16:53:09.487557       1 albingress.go:290] default/sacp-alb: Failed to reconcile state on this ingress
E0913 16:53:09.487566       1 albingress.go:292] default/sacp-alb:  - Failed Listener creation: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
E0913 16:53:09.487570       1 albingress.go:292] default/sacp-alb:      status code: 400, request id: 7e3c2e88-b775-11e8-9b2f-df73d947993a.
E0913 16:53:09.487579       1 albingress.go:295] default/sacp-alb: Will retry to reconcile in 501.08777ms
I0913 16:53:09.487598       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Warning' reason: 'ERROR' Error creating 443 listener: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
        status code: 400, request id: 7e3c2e88-b775-11e8-9b2f-df73d947993a
I0913 16:53:33.222690       1 loadbalancer.go:511] default/sacp-alb: Modifying ELBV2 tags to [  {    Key: "Environment",    Value: "dev"  },  {    Key: "Note",    Value: "k8s"  },  {    Key: "Team",    Value: "devops"  },  {    Key: "kubernetes.io/cluster/sa-dev-eks-1",    Value: "owned"  },  {    Key: "kubernetes.io/ingress-name",    Value: "sacp-alb"  },  {    Key: "kubernetes.io/namespace",    Value: "default"  }].
I0913 16:53:33.222859       1 elbv2.go:519] Request: elasticloadbalancing/AddTags, Payload: {  ResourceArns: ["arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c"],  Tags: [    {      Key: "Environment",      Value: "dev"    },    {      Key: "Note",      Value: "k8s"    },    {      Key: "Team",      Value: "devops"    },    {      Key: "kubernetes.io/cluster/sa-dev-eks-1",      Value: "owned"    },    {      Key: "kubernetes.io/ingress-name",      Value: "sacp-alb"    },    {      Key: "kubernetes.io/namespace",      Value: "default"    }  ]}
I0913 16:53:33.276507       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Normal' reason: 'MODIFY' 3440dd9e-default-sacpalb-bb86 tags modified
I0913 16:53:33.276562       1 listener.go:197] default/sacp-alb: Start Listener creation.
I0913 16:53:33.276762       1 listener.go:240] Request: elasticloadbalancing/CreateListener, Payload: {  Certificates: [{      CertificateArn: "arn:aws:acm:us-east-1:371066304662:certificate/309a6d7a-a4fb-415f-9b4d-718c4c3dda36"    }],  DefaultActions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  LoadBalancerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c",  Port: 443,  Protocol: "HTTPS",  SslPolicy: "ELBSecurityPolicy-2016-08"}
E0913 16:53:33.335800       1 api.go:318] Failed request: elasticloadbalancing/CreateListener, Payload: {  Certificates: [{      CertificateArn: "arn:aws:acm:us-east-1:371066304662:certificate/309a6d7a-a4fb-415f-9b4d-718c4c3dda36"    }],  DefaultActions: [{      RedirectConfig: {        Host: "#{host}",        Path: "/#{path}",        Port: "443",        Protocol: "HTTPS",        Query: "#{query}",        StatusCode: "HTTP_301"      },      Type: "redirect"    }],  LoadBalancerArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:loadbalancer/app/3440dd9e-default-sacpalb-bb86/3787e1828778aa7c",  Port: 443,  Protocol: "HTTPS",  SslPolicy: "ELBSecurityPolicy-2016-08"}, Error: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
        status code: 400, request id: 8c9a5051-b775-11e8-a841-e93d5dfe5193
I0913 16:53:33.335851       1 targetgroup.go:209] default/sacp-alb: Start TargetGroup deletion. ARN: arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31 | Name: 3440dd9e-e5f5084bacfe6b7d2f3.
I0913 16:53:33.335965       1 elbv2.go:319] Request: elasticloadbalancing/DeleteTargetGroup, Payload: {  TargetGroupArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31"}
I0913 16:53:33.336004       1 event.go:221] Event(v1.ObjectReference{Kind:"Ingress", Namespace:"default", Name:"sacp-alb", UID:"7d0ed9fc-b775-11e8-bb39-12e8e94032c2", APIVersion:"extensions/v1beta1", ResourceVersion:"3515806", FieldPath:""}): type: 'Warning' reason: 'ERROR' Error creating 443 listener: InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.
        status code: 400, request id: 8c9a5051-b775-11e8-a841-e93d5dfe5193
E0913 16:53:33.410116       1 api.go:1025] Failed request: elasticloadbalancing/DeleteTargetGroup, Payload: {  TargetGroupArn: "arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31"}, Error: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:371066304662:targetgroup/3440dd9e-e5f5084bacfe6b7d2f3/7f1aa34de9706b31' is currently in use by a listener or a rule
        status code: 400, request id: 8ca636de-b775-11e8-af25-19718a8be12f

@qgriffith-xylem
Copy link

@bigkraig Anything else I can do to help? This is the last thing on my list to get working before I can go live with k8s. So let me know what I can do to assist. Thanks.

@qgriffith-xylem
Copy link

so the new defaultbackend-404 image worked from the stand point it no longer throws a redirect error and 443 listener is created. However everything is throwing a 404 that I try to hit on the ALB. if I hit the app outside of the ALB I don't get a 404 and get the page I expect.

@qgriffith-xylem
Copy link

Ok if I remove ```
IF(all match)

Path is /

From the rule all works as it should but I don't know what is adding that rule  and it will get re-created all the time.

@qgriffith-xylem
Copy link

So I have it working with

spec:
  rules:
    - http:
       paths:
         - path: /*
           backend:
              serviceName: redirect
              servicePort: use-annotation 
    - host: foo
      http:
        paths:
          - path: /*
            backend:
             serviceName: foo
             servicePort: 9090  

I got one nil pointer it seemed to be because I didn't have enough spaces between backend: and serviceName on the new line. Once I fixed that and re-deployed all was well. Great work @bigkraig

@qgriffith-xylem
Copy link

Is it OK to swtich to latest now or can you let us know when it is merged? @bigkraig

@bigkraig
Copy link

@qgriffith-xylem it'll be merged soon but we are still a little bit away from the next beta release

bigkraig added a commit that referenced this issue Oct 1, 2018
@stevenpall
Copy link

For reference, here is my working ingress object:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/actions.redirect: '{"Type": "redirect", "RedirectConfig":
      { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/certificate-arn: redacted
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/subnets: redacted
  name: test
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: redirect
          servicePort: use-annotation
        path: /*
  - host: test.com
    http:
      paths:
      - backend:
          serviceName: test
          servicePort: 80
        path: /*

@danopia danopia changed the title Feature req: HTTP -> HTTPS redirects (via newly added ALB feature) Feature req: HTTP -> HTTPS redirects (ALB-native) Oct 24, 2018
@AndresPineros
Copy link

Guys, please add this as an example in the repository. This is something very common when using ALBs.

@M00nF1sh
Copy link
Collaborator

@AndresPineros
Hi, the docs are now available in https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/tasks/ssl_redirect/ 😄

@meappy
Copy link

meappy commented Nov 13, 2019

I understand this topic is marked as closed, but I was wondering if there is a way to stop :443 from being appended to #{host}?

I've tried doing this (I note a comment made), but does not appear to be valid syntax. Not at least from internal/alb/ls/rules_test.go

    alb.ingress.kubernetes.io/actions.ssl-redirect: >-
      {   
        "Type": "redirect",
        "RedirectConfig": {
          "URI": "https://#{host}/#{path}?#{query}",
          "StatusCode": "HTTP_301"
        }   
      } 

Perhaps a URI feature can be added for config flexibility?

:443 shows up with curl

$ curl -k  -H 'Host: www.example.com' -IL http://xxx.ap-southeast-2.elb.amazonaws.com
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Wed, 13 Nov 2019 03:02:37 GMT
Content-Type: text/html
Content-Length: 150
Connection: keep-alive
Location: https://www.example.com:443/

HTTP/2 301
server: nginx
date: Wed, 13 Nov 2019 03:02:38 GMT
content-type: text/html; charset=UTF-8
x-powered-by: PHP/7.0.33
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
x-redirect-by: WordPress
set-cookie: PHPSESSID=9b476f35e469fc2c771d5caedfa8435d; path=/
set-cookie: pmpro_visit=1; path=/
location: https://example.com/
alt-svc: quic=":443"; ma=86400; v="43,39"

Screenshot from AWS console ALB Rules

Screen Shot 2019-11-13 at 1 32 12 pm

@agconti
Copy link

agconti commented Mar 19, 2020

@stevenpall thanks for posting your working version! It helped me a ton in figuring this out.

@M00nF1sh I think it would be huge help to add an example hostname ingress configuration to the documentation for those looking to configure ssl-redirects. The hostname configuration is more tricky than the path based configuration because with hostnames both the SSL redirect and the service want to use path: "/*".

If you're into adding this to the docs, I can open a PR!

@apolegoshko
Copy link

apolegoshko commented Dec 11, 2020

Unfortunately, loadbalancer which is created by this Ingress resource is not acceptable by AWS Security Hub. When I'm trying to apply ssl redirect to default rule (spec.backend), I'm getting following error in logs. @M00nF1sh

E1211 13:52:41.629511       1 controller.go:217] kubebuilder/controller "msg"="Reconciler error" "error"="failed to reconcile listeners due to failed to reconcile listener due to InvalidLoadBalancerAction: The redirect configuration is not valid because it creates a loop.\n\tstatus code: 400, request id: 65e65437-ec47-41c5-9231-798beeb212da"  "controller"="alb-ingress-controller" "request"={"Namespace":"default","Name":"app"}

As far as I understand, the loop can appear because of applying the same default rule to both listeners 80 and 443.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature Categorizes issue or PR as related to a new feature.
Projects
None yet
Development

No branches or pull requests