package exposition import ( certManager "antoine-roux.tk/projects/go/pulumi-library/crds/kubernetes/certmanager/v1" traefik "antoine-roux.tk/projects/go/pulumi-library/crds/kubernetes/traefik/v1alpha1" "fmt" "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1" meta "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/meta/v1" networking "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/networking/v1" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) type IngressConfiguration struct { Name string Dns string ResponseHeaders *traefik.MiddlewareSpecHeadersArgs services []IngressServices } type IngressServices struct { Service *v1.Service Path string } func NewIngressConfiguration(name string, dns string, allowAllOrigin bool, services []IngressServices) *IngressConfiguration { ingressConfiguration := &IngressConfiguration{ Name: name, Dns: dns, services: services, } if allowAllOrigin { ingressConfiguration.ResponseHeaders = &traefik.MiddlewareSpecHeadersArgs{ AccessControlAllowOriginList: toPulumiStringArray([]string{"*"}), } } return ingressConfiguration } func toPulumiStringArray(values []string) pulumi.StringArray { array := pulumi.StringArray{} for _, value := range values { array = append(array, pulumi.String(value)) } return array } func (ingress *IngressConfiguration) CreateIngress( ctx *pulumi.Context, namespace *v1.Namespace, parentApplication pulumi.Resource, certificate *certManager.Certificate, ) error { var middlewares pulumi.StringInput if ingress.ResponseHeaders != nil { headerMiddleware, err := ingress.createMiddlewareAddResponseHeader(ctx, namespace, parentApplication) if err != nil { return err } middlewares = pulumi.All(namespace.Metadata.Name().Elem(), headerMiddleware.Metadata.Name().Elem()).ApplyT(func(args []interface{}) string { return fmt.Sprintf("kube-ingress-gzip-compress@kubernetescrd,%s-%s@kubernetescrd", args[0], args[1]) }).(pulumi.StringOutput) } else { middlewares = pulumi.String("kube-ingress-gzip-compress@kubernetescrd") } ingressAnnotations := pulumi.StringMap{ "traefik.ingress.kubernetes.io/router.middlewares": middlewares, "traefik.ingress.kubernetes.io/router.entrypoints": pulumi.String("websecure"), } // https routing var ingressPaths networking.HTTPIngressPathArray for _, service := range ingress.services { ingressPaths = append(ingressPaths, networking.HTTPIngressPathArgs{ Path: pulumi.String(service.Path), PathType: pulumi.String("Prefix"), Backend: &networking.IngressBackendArgs{ Service: &networking.IngressServiceBackendArgs{ Name: service.Service.Metadata.Name().Elem(), Port: &networking.ServiceBackendPortArgs{ Name: pulumi.String("exposed-port"), }, }, }, }) } // create http redirect to https err := ingress.createHttpRedirectIngress(ctx, namespace, parentApplication, ingressPaths) if err != nil { return err } _, err = networking.NewIngress(ctx, fmt.Sprintf("%s-https", ingress.Name), &networking.IngressArgs{ Metadata: &meta.ObjectMetaArgs{ Namespace: namespace.Metadata.Name(), Labels: pulumi.StringMap{ "app.kubernetes.io/part-of": pulumi.String(ingress.Name), "app.kubernetes.io/managed-by": pulumi.String("pulumi"), }, Annotations: ingressAnnotations, }, Spec: &networking.IngressSpecArgs{ IngressClassName: pulumi.String("traefik-internal"), Rules: &networking.IngressRuleArray{ networking.IngressRuleArgs{ Host: pulumi.StringPtr(ingress.Dns), Http: &networking.HTTPIngressRuleValueArgs{ Paths: ingressPaths, }, }, }, Tls: &networking.IngressTLSArray{ networking.IngressTLSArgs{ Hosts: pulumi.StringArray{ pulumi.String(ingress.Dns), }, SecretName: certificate.Spec.SecretName(), }, }, }, }, pulumi.Parent(parentApplication)) return err } func (ingress *IngressConfiguration) createHttpRedirectIngress( ctx *pulumi.Context, namespace *v1.Namespace, parentApplication pulumi.Resource, paths networking.HTTPIngressPathArray, ) error { ingressAnnotations := pulumi.StringMap{ "traefik.ingress.kubernetes.io/router.middlewares": pulumi.String("kube-ingress-gzip-compress@kubernetescrd,kube-ingress-redirect-scheme-https@kubernetescrd"), "traefik.ingress.kubernetes.io/router.entrypoints": pulumi.String("web"), } _, err := networking.NewIngress(ctx, fmt.Sprintf("%s-http", ingress.Name), &networking.IngressArgs{ Metadata: &meta.ObjectMetaArgs{ Namespace: namespace.Metadata.Name(), Labels: pulumi.StringMap{ "app.kubernetes.io/part-of": pulumi.String(ingress.Name), "app.kubernetes.io/managed-by": pulumi.String("pulumi"), }, Annotations: ingressAnnotations, }, Spec: &networking.IngressSpecArgs{ IngressClassName: pulumi.String("traefik-internal"), Rules: &networking.IngressRuleArray{ networking.IngressRuleArgs{ Host: pulumi.String(ingress.Dns), Http: &networking.HTTPIngressRuleValueArgs{ Paths: paths, }, }, }, }, }, pulumi.Parent(parentApplication)) if err != nil { return err } return nil } func (ingress *IngressConfiguration) createMiddlewareAddResponseHeader( ctx *pulumi.Context, namespace *v1.Namespace, parentApplication pulumi.Resource, ) (*traefik.Middleware, error) { middlewareName := fmt.Sprintf("%s-response-header-middleware", ingress.Name) return traefik.NewMiddleware(ctx, middlewareName, &traefik.MiddlewareArgs{ Metadata: &meta.ObjectMetaArgs{ Namespace: namespace.Metadata.Name(), Labels: pulumi.StringMap{ "app.kubernetes.io/part-of": pulumi.String(ingress.Name), "app.kubernetes.io/managed-by": pulumi.String("pulumi"), }, }, Spec: &traefik.MiddlewareSpecArgs{ Headers: ingress.ResponseHeaders, }, }, pulumi.Parent(parentApplication)) }