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

CNF-13958: Enable TLS verification for in-cluster deployments #177

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions internal/authentication/handler_wrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -716,10 +716,6 @@ var _ = Describe("Handler wapper", func() {
It("Doesn't load insecure keys by default", func() {
var err error

// TODO(alegacy): Remove this override once it is fixed for production
err = os.Setenv(utils.TLSSkipVerifyEnvName, "false")
Expect(err).ToNot(HaveOccurred())

// Prepare the server:
server, ca := MakeTCPTLSServer()
defer func() {
Expand Down
6 changes: 4 additions & 2 deletions internal/controllers/utils/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ var (
// Default values for backend URL and token:
const (
defaultBackendURL = "https://kubernetes.default.svc"
defaultBackendTokenFile = "/run/secrets/kubernetes.io/serviceaccount/token" // nolint: gosec // hardcoded path only
defaultBackendTokenFile = "/run/secrets/kubernetes.io/serviceaccount/token" // nolint: gosec // hardcoded path only
defaultBackendCABundle = "/run/secrets/kubernetes.io/serviceaccount/ca.crt" // nolint: gosec // hardcoded path only
defaultServiceCAFile = "/run/secrets/kubernetes.io/serviceaccount/service-ca.crt" // nolint: gosec // hardcoded path only
)

// ClusterInstance template constants
Expand Down Expand Up @@ -128,5 +130,5 @@ const (
// Environment variable names
const (
TLSSkipVerifyEnvName = "INSECURE_SKIP_VERIFY"
TLSSkipVerifyDefaultValue = true // TODO(alegacy): need to set to false for production
TLSSkipVerifyDefaultValue = false
)
64 changes: 63 additions & 1 deletion internal/controllers/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ package utils
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"os"
"reflect"
"slices"
"strconv"
"strings"
"text/template"

"k8s.io/apimachinery/pkg/util/net"
ctrl "sigs.k8s.io/controller-runtime"

sprig "github.com/go-task/slim-sprig/v3"
"github.com/xeipuuv/gojsonschema"

Expand All @@ -23,7 +29,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/yaml"
Expand Down Expand Up @@ -720,3 +725,60 @@ func GetTLSSkipVerify() bool {

return result
}

// loadDefaultCABundles loads the default service account and ingress CA bundles. This should only be invoked if TLS
// verification has not been disabled since the expectation is that it will only need to be disabled when testing as a
// standalone binary in which case the paths to the bundles won't be present. Otherwise, we always expect the bundles
// to be present when running in-cluster.
func loadDefaultCABundles(config *tls.Config) error {
config.RootCAs = x509.NewCertPool()
if data, err := os.ReadFile(defaultBackendCABundle); err != nil {
// This should not happen unless the binary is being tested in standalone mode in which case the developer
// should have disabled the TLS verification which would prevent this function from being invoked.
return fmt.Errorf("failed to read CA bundle '%s': %w", defaultBackendCABundle, err)
// This should not happen, but if it does continue anyway
} else {
// This will enable accessing public facing API endpoints signed by the default ingress controller certificate
config.RootCAs.AppendCertsFromPEM(data)
}

if data, err := os.ReadFile(defaultServiceCAFile); err != nil {
return fmt.Errorf("failed to read service CA file '%s': %w", defaultServiceCAFile, err)
} else {
// This will enable accessing internal services signed by the service account signer.
config.RootCAs.AppendCertsFromPEM(data)
}

return nil
}

// GetDefaultTLSConfig sets the TLS configuration attributes appropriately to enable communication between internal
// services and accessing the public facing API endpoints.
func GetDefaultTLSConfig(config *tls.Config) (*tls.Config, error) {
if config == nil {
config = &tls.Config{MinVersion: tls.VersionTLS12}
}

// Allow developers to override the TLS verification
config.InsecureSkipVerify = GetTLSSkipVerify()
if !config.InsecureSkipVerify {
// TLS verification is enabled therefore we need to load the CA bundles that are injected into our filesystem
// automatically; which happens since we are defined as using a service-account
err := loadDefaultCABundles(config)
if err != nil {
return nil, fmt.Errorf("error loading default CABundles: %w", err)
}
}

return config, nil
}

// GetDefaultBackendTransport returns an HTTP transport with the proper TLS defaults set.
func GetDefaultBackendTransport() (http.RoundTripper, error) {
tlsConfig, err := GetDefaultTLSConfig(&tls.Config{MinVersion: tls.VersionTLS12})
if err != nil {
return nil, err
}

return net.SetTransportDefaults(&http.Transport{TLSClientConfig: tlsConfig}), nil
}
13 changes: 5 additions & 8 deletions internal/service/alarm_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ package service

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
neturl "net/url"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/jq"
"github.com/openshift-kni/oran-o2ims/internal/k8s"
Expand Down Expand Up @@ -154,11 +151,11 @@ func (b *AlarmFetcherBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
13 changes: 5 additions & 8 deletions internal/service/alarm_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ package service

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
"slices"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/search"
)
Expand Down Expand Up @@ -150,11 +147,11 @@ func (b *AlarmHandlerBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
15 changes: 6 additions & 9 deletions internal/service/deployment_manager_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package service

import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
Expand All @@ -26,11 +25,9 @@ import (
"slices"
"sync"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/imdario/mergo"
jsoniter "github.com/json-iterator/go"
"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -177,11 +174,11 @@ func (b *DeploymentManagerHandlerBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.loggingWrapper != nil {
backendTransport = b.loggingWrapper(backendTransport)
}
Expand Down
13 changes: 5 additions & 8 deletions internal/service/resource_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package service
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
Expand All @@ -26,8 +25,6 @@ import (
"net/http"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/k8s"
"github.com/openshift-kni/oran-o2ims/internal/model"
Expand Down Expand Up @@ -137,11 +134,11 @@ func (b *ResourceFetcherBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
16 changes: 7 additions & 9 deletions internal/service/resource_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@ package service

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
"slices"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/itchyny/gojq"
"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/graphql"
Expand Down Expand Up @@ -149,11 +147,11 @@ func (b *ResourceHandlerBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
13 changes: 5 additions & 8 deletions internal/service/resource_pool_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package service
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
Expand All @@ -27,8 +26,6 @@ import (
"strings"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/graphql"
"github.com/openshift-kni/oran-o2ims/internal/jq"
Expand Down Expand Up @@ -148,11 +145,11 @@ func (b *ResourcePoolFetcherBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
14 changes: 6 additions & 8 deletions internal/service/resource_pool_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ package service

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"
"slices"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/graphql"
"github.com/openshift-kni/oran-o2ims/internal/model"
Expand Down Expand Up @@ -145,11 +143,11 @@ func (b *ResourcePoolHandlerBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
14 changes: 6 additions & 8 deletions internal/service/resource_type_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ package service

import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net/http"

"github.com/openshift-kni/oran-o2ims/internal/controllers/utils"
"k8s.io/apimachinery/pkg/util/net"

"github.com/openshift-kni/oran-o2ims/internal/data"
"github.com/openshift-kni/oran-o2ims/internal/files"
"github.com/openshift-kni/oran-o2ims/internal/model"
Expand Down Expand Up @@ -146,11 +144,11 @@ func (b *ResourceTypeHandlerBuilder) Build() (
}

// Create the HTTP client that we will use to connect to the backend:
var backendTransport http.RoundTripper = net.SetTransportDefaults(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: utils.GetTLSSkipVerify(), // nolint: gosec // defaulted to false; logged if disabled
},
})
backendTransport, err := utils.GetDefaultBackendTransport()
if err != nil {
err = fmt.Errorf("failed to create default HTTP backend transport: %w", err)
return
}
if b.transportWrapper != nil {
backendTransport = b.transportWrapper(backendTransport)
}
Expand Down
Loading