Skip to content

Commit

Permalink
Support no-tls-verify (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
STRRL committed Jun 30, 2023
1 parent 7ec359a commit b1ff094
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 27 deletions.
17 changes: 15 additions & 2 deletions pkg/cloudflare-controller/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cloudflarecontroller

import (
"context"
"strings"

"github.com/STRRL/cloudflare-tunnel-ingress-controller/pkg/exposure"
"github.com/cloudflare/cloudflare-go"
"github.com/pkg/errors"
Expand All @@ -12,9 +14,20 @@ func fromExposureToCloudflareIngress(ctx context.Context, exposure exposure.Expo
return nil, errors.Errorf("exposure %s is deleted, should not generate cloudflare ingress for it", exposure.Hostname)
}

return &cloudflare.UnvalidatedIngressRule{
result := cloudflare.UnvalidatedIngressRule{
Hostname: exposure.Hostname,
Path: exposure.PathPrefix,
Service: exposure.ServiceTarget,
}, nil
}

if strings.HasPrefix(exposure.ServiceTarget, "https://") {
result.OriginRequest = &cloudflare.OriginRequestConfig{}
if exposure.ProxySSLVerifyEnabled == nil {
result.OriginRequest.NoTLSVerify = boolPointer(true)
} else {
result.OriginRequest.NoTLSVerify = boolPointer(!*exposure.ProxySSLVerifyEnabled)
}
}

return &result, nil
}
64 changes: 62 additions & 2 deletions pkg/cloudflare-controller/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package cloudflarecontroller

import (
"context"
"github.com/STRRL/cloudflare-tunnel-ingress-controller/pkg/exposure"
"github.com/cloudflare/cloudflare-go"
"reflect"
"testing"

"github.com/STRRL/cloudflare-tunnel-ingress-controller/pkg/exposure"
"github.com/cloudflare/cloudflare-go"
)

func Test_fromExposureToCloudflareIngress(t *testing.T) {
Expand Down Expand Up @@ -67,6 +68,65 @@ func Test_fromExposureToCloudflareIngress(t *testing.T) {
OriginRequest: nil,
},
wantErr: false,
}, {
name: "https should enable no-tls-verify by default",
args: args{
ctx: context.Background(),
exposure: exposure.Exposure{
Hostname: "ingress.example.com",
ServiceTarget: "https://10.0.0.1:443",
PathPrefix: "/",
IsDeleted: false,
},
},
want: &cloudflare.UnvalidatedIngressRule{
Hostname: "ingress.example.com",
Path: "/",
Service: "https://10.0.0.1:443",
OriginRequest: &cloudflare.OriginRequestConfig{
NoTLSVerify: boolPointer(true),
},
},
}, {
name: "https with no-tls-verify enabled",
args: args{
ctx: context.Background(),
exposure: exposure.Exposure{
Hostname: "ingress.example.com",
ServiceTarget: "https://10.0.0.1:443",
PathPrefix: "/",
IsDeleted: false,
ProxySSLVerifyEnabled: boolPointer(false),
},
},
want: &cloudflare.UnvalidatedIngressRule{
Hostname: "ingress.example.com",
Path: "/",
Service: "https://10.0.0.1:443",
OriginRequest: &cloudflare.OriginRequestConfig{
NoTLSVerify: boolPointer(true),
},
},
}, {
name: "https with no-tls-verify disabled",
args: args{
ctx: context.Background(),
exposure: exposure.Exposure{
Hostname: "ingress.example.com",
ServiceTarget: "https://10.0.0.1:443",
PathPrefix: "/",
IsDeleted: false,
ProxySSLVerifyEnabled: boolPointer(true),
},
},
want: &cloudflare.UnvalidatedIngressRule{
Hostname: "ingress.example.com",
Path: "/",
Service: "https://10.0.0.1:443",
OriginRequest: &cloudflare.OriginRequestConfig{
NoTLSVerify: boolPointer(false),
},
},
},
}
for _, tt := range tests {
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/ingress-controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (i *IngressController) Reconcile(ctx context.Context, request reconcile.Req
var allExposures []exposure.Exposure
for _, ingress := range ingresses {
// best effort to extract exposures from all ingresses
exposures, err := FromIngressToExposure(ctx, i.kubeClient, ingress)
exposures, err := FromIngressToExposure(ctx, i.logger, i.kubeClient, ingress)
if err != nil {
i.logger.Info("extract exposures from ingress, skipped", "triggered-by", request.NamespacedName, "ingress", fmt.Sprintf("%s/%s", ingress.Namespace, ingress.Name), "error", err)
}
Expand Down
49 changes: 39 additions & 10 deletions pkg/controller/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@ package controller
import (
"context"
"fmt"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/STRRL/cloudflare-tunnel-ingress-controller/pkg/exposure"
"github.com/go-logr/logr"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/types"
)

func FromIngressToExposure(ctx context.Context, kubeClient client.Client, ingress networkingv1.Ingress) ([]exposure.Exposure, error) {
func FromIngressToExposure(ctx context.Context, logger logr.Logger, kubeClient client.Client, ingress networkingv1.Ingress) ([]exposure.Exposure, error) {
isDeleted := false

if ingress.DeletionTimestamp != nil {
isDeleted = true
}

var tlsHosts []string
for _, tls := range ingress.Spec.TLS {
tlsHosts = append(tlsHosts, tls.Hosts...)
if len(ingress.Spec.TLS) > 0 {
logger.Info("ingress has tls specified, SSL Passthrough is not supported, it will be ignored.")
}

var result []exposure.Exposure
Expand All @@ -33,8 +34,26 @@ func FromIngressToExposure(ctx context.Context, kubeClient client.Client, ingres
hostname := rule.Host

scheme := "http"
if stringSliceContains(tlsHosts, rule.Host) {
scheme = "https"

if backendProtocol, ok := getAnnotation(ingress.Annotations, AnnotationBackendProtocol); ok {
scheme = backendProtocol
}

var proxySSLVerifyEnabled *bool

if proxySSLVerify, ok := getAnnotation(ingress.Annotations, AnnotationProxySSLVerify); ok {
if proxySSLVerify == AnnotationProxySSLVerifyOn {
proxySSLVerifyEnabled = boolPointer(true)
} else if proxySSLVerify == AnnotationProxySSLVerifyOff {
proxySSLVerifyEnabled = boolPointer(false)
} else {
return nil, errors.Errorf(
"invalid value for annotation %s, available values: \"%s\" or \"%s\"",
AnnotationProxySSLVerify,
AnnotationProxySSLVerifyOn,
AnnotationProxySSLVerifyOff,
)
}
}

for _, path := range rule.HTTP.Paths {
Expand Down Expand Up @@ -80,10 +99,11 @@ func FromIngressToExposure(ctx context.Context, kubeClient client.Client, ingres
pathPrefix := path.Path

result = append(result, exposure.Exposure{
Hostname: hostname,
ServiceTarget: fmt.Sprintf("%s://%s:%d", scheme, host, port),
PathPrefix: pathPrefix,
IsDeleted: isDeleted,
Hostname: hostname,
ServiceTarget: fmt.Sprintf("%s://%s:%d", scheme, host, port),
PathPrefix: pathPrefix,
IsDeleted: isDeleted,
ProxySSLVerifyEnabled: proxySSLVerifyEnabled,
})
}
}
Expand All @@ -99,3 +119,12 @@ func getPortWithName(ports []v1.ServicePort, portName string) (bool, int32) {
}
return false, 0
}

func getAnnotation(annotations map[string]string, key string) (string, bool) {
value, ok := annotations[key]
return value, ok
}

func boolPointer(b bool) *bool {
return &b
}
9 changes: 9 additions & 0 deletions pkg/controller/weel_known_annotations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package controller

// AnnotationProxySSLVerify is the annotation key for proxy-ssl-verify, available values: "on" or "off", default "off".
const AnnotationProxySSLVerify = "cloudflare-tunnel-ingress-controller.strrl.dev/proxy-ssl-verify"
const AnnotationProxySSLVerifyOn = "on"
const AnnotationProxySSLVerifyOff = "off"

// AnnotationBackendProtocol is the annotation key for proxy-backend-protocol, default "http".
const AnnotationBackendProtocol = "cloudflare-tunnel-ingress-controller.strrl.dev/backend-protocol"
2 changes: 2 additions & 0 deletions pkg/exposure/exposure.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ type Exposure struct {
PathPrefix string
// IsDeleted is the flag to indicate if the exposure is deleted.
IsDeleted bool
// ProxySSLVerifyEnabled is the flag to indicate if the exposure should skip TLS verification.
ProxySSLVerifyEnabled *bool
}
Loading

0 comments on commit b1ff094

Please sign in to comment.