Skip to content

Commit

Permalink
customizable TLS key and cert on application HTTPS endpoint
Browse files Browse the repository at this point in the history
Signed-off-by: Haoyu Sun <[email protected]>
  • Loading branch information
raptorsun committed Sep 25, 2024
1 parent 97b1945 commit cb520d6
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 36 deletions.
16 changes: 13 additions & 3 deletions api/v1alpha1/olsconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ type OLSSpec struct {
// User data collection switches
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="User Data Collection"
UserDataCollection UserDataCollectionSpec `json:"userDataCollection,omitempty"`

UseUserProvidedTLSCerts bool `json:"useUserProvidedTLSCerts,omitempty"`
// TLS configuration of the Lightspeed backend's HTTPS endpoint
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="TLS Configuration"
TLSConfig *TLSConfig `json:"tlsConfig,omitempty"`
// Additional CA certificates for TLS communication between OLS service and LLM Provider
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Additional CA Configmap",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
AdditionalCAConfigMapRef *corev1.LocalObjectReference `json:"additionalCAConfigMapRef,omitempty"`
Expand Down Expand Up @@ -126,7 +127,10 @@ type ConsoleContainerConfig struct {
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Node Selector",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:nodeSelector"}
NodeSelector map[string]string `json:"nodeSelector,omitempty"`

// Certificate Authority (CA) certificate used by the console proxy endpoint.
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="CA Certificate",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:caCertificate"}
// +kubebuilder:validation:Pattern=`^-----BEGIN CERTIFICATE-----([\s\S]*)-----END CERTIFICATE-----\s?$`
// +optional
CAcertificate string `json:"caCertificate,omitempty"`
}

Expand Down Expand Up @@ -259,6 +263,12 @@ type OLSDataCollectorSpec struct {
LogLevel string `json:"logLevel,omitempty"`
}

type TLSConfig struct {
// KeySecretRef is the secret that holds the TLS key.
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Key Secret"
KeyCertSecretRef corev1.LocalObjectReference `json:"keyCertSecretRef,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster
Expand Down
21 changes: 21 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions bundle/manifests/lightspeed-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ metadata:
]
capabilities: Basic Install
console.openshift.io/operator-monitoring-default: "true"
createdAt: "2024-08-30T09:59:16Z"
createdAt: "2024-09-17T17:01:48Z"
features.operators.openshift.io/cnf: "false"
features.operators.openshift.io/cni: "false"
features.operators.openshift.io/csi: "false"
Expand Down Expand Up @@ -161,6 +161,11 @@ spec:
- description: Console container settings.
displayName: Console Container
path: ols.deployment.console
- description: Certificate Authority (CA) certificate used by the console proxy endpoint.
displayName: CA Certificate
path: ols.deployment.console.caCertificate
x-descriptors:
- urn:alm:descriptor:com.tectonic.ui:caCertificate
- displayName: Node Selector
path: ols.deployment.console.nodeSelector
x-descriptors:
Expand Down Expand Up @@ -200,6 +205,12 @@ spec:
- description: Replacement for the matched pattern.
displayName: Replace With
path: ols.queryFilters[0].replaceWith
- description: TLS configuration of the Lightspeed backend's HTTPS endpoint
displayName: TLS Configuration
path: ols.tlsConfig
- description: KeySecretRef is the secret that holds the TLS key.
displayName: Key Secret
path: ols.tlsConfig.keyCertSecretRef
- description: User data collection switches
displayName: User Data Collection
path: ols.userDataCollection
Expand Down Expand Up @@ -535,8 +546,8 @@ spec:
type: AllNamespaces
keywords:
- ai
- openshift
- assistant
- openshift
- llm
links:
- name: Lightspeed Operator
Expand Down
23 changes: 23 additions & 0 deletions bundle/manifests/ols.openshift.io_olsconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ spec:
console:
description: Console container settings.
properties:
caCertificate:
description: Certificate Authority (CA) certificate used
by the console proxy endpoint.
pattern: ^-----BEGIN CERTIFICATE-----([\s\S]*)-----END
CERTIFICATE-----\s?$
type: string
nodeSelector:
additionalProperties:
type: string
Expand Down Expand Up @@ -483,6 +489,23 @@ spec:
type: string
type: object
type: array
tlsConfig:
description: TLS configuration of the Lightspeed backend's HTTPS
endpoint
properties:
keyCertSecretRef:
description: KeySecretRef is the secret that holds the TLS
key.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: object
userDataCollection:
description: User data collection switches
properties:
Expand Down
23 changes: 21 additions & 2 deletions config/crd/bases/ols.openshift.io_olsconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ spec:
description: Console container settings.
properties:
caCertificate:
description: Certificate Authority (CA) certificate used
by the console proxy endpoint.
pattern: ^-----BEGIN CERTIFICATE-----([\s\S]*)-----END
CERTIFICATE-----\s?$
type: string
nodeSelector:
additionalProperties:
Expand Down Expand Up @@ -485,8 +489,23 @@ spec:
type: string
type: object
type: array
useUserProvidedTLSCerts:
type: boolean
tlsConfig:
description: TLS configuration of the Lightspeed backend's HTTPS
endpoint
properties:
keyCertSecretRef:
description: KeySecretRef is the secret that holds the TLS
key.
properties:
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
type: string
type: object
x-kubernetes-map-type: atomic
type: object
userDataCollection:
description: User data collection switches
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ spec:
- description: Console container settings.
displayName: Console Container
path: ols.deployment.console
- description: Certificate Authority (CA) certificate used by the console proxy
endpoint.
displayName: CA Certificate
path: ols.deployment.console.caCertificate
x-descriptors:
- urn:alm:descriptor:com.tectonic.ui:caCertificate
- displayName: Node Selector
path: ols.deployment.console.nodeSelector
x-descriptors:
Expand Down Expand Up @@ -169,6 +175,12 @@ spec:
- description: Replacement for the matched pattern.
displayName: Replace With
path: ols.queryFilters[0].replaceWith
- description: TLS configuration of the Lightspeed backend's HTTPS endpoint
displayName: TLS Configuration
path: ols.tlsConfig
- description: KeySecretRef is the secret that holds the TLS key.
displayName: Key Secret
path: ols.tlsConfig.keyCertSecretRef
- description: User data collection switches
displayName: User Data Collection
path: ols.userDataCollection
Expand Down
1 change: 0 additions & 1 deletion hack/custom_certs/cr-with-custom-certs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ spec:
defaultModel: ibm/granite-13b-chat-v2
defaultProvider: bam
logLevel: INFO
useUserProvidedTLSCerts: true
deployment:
replicas: 1
console:
Expand Down
20 changes: 11 additions & 9 deletions hack/custom_certs/generate-certs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,42 @@ CA_CERT="$CERT_DIR/ca.crt"
PRIVATE_KEY="$CERT_DIR/tls.key"
CERTIFICATE="$CERT_DIR/tls.crt"
DAYS_VALID=365
SECRET_NAME="lightspeed-tls"
SECRET_NAME="user-app-tls"
CM_NAME="user-app-ca"
NAMESPACE="openshift-lightspeed"

# Create directory for certificates if it doesn't exist
mkdir -p "$CERT_DIR"

# Generate CA private key and self-signed CA certificate
openssl req -x509 -newkey rsa:4096 -sha256 -days "$DAYS_VALID" -nodes \
-keyout "$CA_KEY" -out "$CA_CERT" -subj "/CN=MyCA" \
-addext "subjectAltName=DNS:MyCA"
-keyout "$CA_KEY" -out "$CA_CERT" -subj "/CN=MyCA" \
-addext "subjectAltName=DNS:MyCA"

echo "CA certificate and private key have been generated in $CERT_DIR"

# Generate private key and certificate signing request (CSR) for the server
openssl req -new -newkey rsa:4096 -nodes -keyout "$PRIVATE_KEY" -out "$CERT_DIR/server.csr" \
-subj "/CN=lightspeed-app-server" -addext "subjectAltName=DNS:lightspeed-app-server,DNS:lightspeed-app-server.openshift-lightspeed.svc.cluster.local,IP:127.0.0.1,IP:::1"
-subj "/CN=lightspeed-app-server" -addext "subjectAltName=DNS:lightspeed-app-server,DNS:lightspeed-app-server.openshift-lightspeed.svc.cluster.local,IP:127.0.0.1,IP:::1"

# Sign the server certificate with the CA certificate
openssl x509 -req -in "$CERT_DIR/server.csr" -CA "$CA_CERT" -CAkey "$CA_KEY" -CAcreateserial \
-out "$CERTIFICATE" -days "$DAYS_VALID" -sha256 -extfile <(echo "subjectAltName=DNS:lightspeed-app-server,DNS:lightspeed-app-server.openshift-lightspeed.svc.cluster.local,IP:127.0.0.1,IP:::1")
-out "$CERTIFICATE" -days "$DAYS_VALID" -sha256 -extfile <(echo "subjectAltName=DNS:lightspeed-app-server,DNS:lightspeed-app-server.openshift-lightspeed.svc.cluster.local,IP:127.0.0.1,IP:::1")

echo "Server certificate signed by CA has been generated in $CERT_DIR"

# Generate the Kubernetes Secret YAML manifest for the TLS certificate and key for the ols-server
cat <<EOF > "$CERT_DIR/$SECRET_NAME.yaml"

cat <<EOF >"$CERT_DIR/$SECRET_NAME.yaml"
apiVersion: v1
kind: Secret
metadata:
name: $SECRET_NAME
namespace: $NAMESPACE
type: kubernetes.io/tls
data:
tls.crt: $(base64 < "$CERTIFICATE")
tls.key: $(base64 < "$PRIVATE_KEY")
tls.crt: $(base64 <"$CERTIFICATE" | tr -d '\n')
tls.key: $(base64 <"$PRIVATE_KEY" | tr -d '\n')
EOF

echo "Kubernetes Secret manifest for TLS has been generated at $CERT_DIR/$SECRET_NAME.yaml"
echo "Kubernetes Secret manifest for TLS has been generated at $CERT_DIR/$SECRET_NAME.yaml"
22 changes: 15 additions & 7 deletions internal/controller/ols_app_server_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ func (r *OLSConfigReconciler) generateOLSConfigMap(ctx context.Context, cr *olsv

dataCollectorEnabled, _ := r.dataCollectorEnabled(cr)

tlsConfig := TLSConfig{
TLSCertificatePath: path.Join(OLSAppCertsMountRoot, OLSCertsSecretName, "tls.crt"),
TLSKeyPath: path.Join(OLSAppCertsMountRoot, OLSCertsSecretName, "tls.key"),
}

if cr.Spec.OLSConfig.TLSConfig != nil && cr.Spec.OLSConfig.TLSConfig.KeyCertSecretRef.Name != "" {
tlsConfig.TLSCertificatePath = path.Join(OLSAppCertsMountRoot, cr.Spec.OLSConfig.TLSConfig.KeyCertSecretRef.Name, "tls.crt")
tlsConfig.TLSKeyPath = path.Join(OLSAppCertsMountRoot, cr.Spec.OLSConfig.TLSConfig.KeyCertSecretRef.Name, "tls.key")
}

olsConfig := OLSConfig{
DefaultModel: cr.Spec.OLSConfig.DefaultModel,
DefaultProvider: cr.Spec.OLSConfig.DefaultProvider,
Expand All @@ -198,10 +208,7 @@ func (r *OLSConfigReconciler) generateOLSConfigMap(ctx context.Context, cr *olsv
UvicornLogLevel: cr.Spec.OLSConfig.LogLevel,
},
ConversationCache: conversationCache,
TLSConfig: TLSConfig{
TLSCertificatePath: path.Join(OLSAppCertsMountRoot, OLSCertsSecretName, "tls.crt"),
TLSKeyPath: path.Join(OLSAppCertsMountRoot, OLSCertsSecretName, "tls.key"),
},
TLSConfig: tlsConfig,
ReferenceContent: ReferenceContent{
ProductDocsIndexPath: "/app-root/vector_db/ocp_product_docs/" + major + "." + minor,
ProductDocsIndexId: "ocp-product-docs-" + major + "_" + minor,
Expand Down Expand Up @@ -322,10 +329,11 @@ func (r *OLSConfigReconciler) getAdditionalCAFileNames(cr *olsv1alpha1.OLSConfig
func (r *OLSConfigReconciler) generateService(cr *olsv1alpha1.OLSConfig) (*corev1.Service, error) {
annotations := map[string]string{}

// Check if the flag for user-provided TLS certs is set
if !cr.Spec.OLSConfig.UseUserProvidedTLSCerts {
// Add the service-served certs annotations only if the flag is not set
// Let service-ca operator generate a TLS certificate if the user does not provide one
if cr.Spec.OLSConfig.DeploymentConfig.ConsoleContainer.CAcertificate == "" {
annotations[ServingCertSecretAnnotationKey] = OLSCertsSecretName
} else {
delete(annotations, ServingCertSecretAnnotationKey)
}

service := corev1.Service{
Expand Down
Loading

0 comments on commit cb520d6

Please sign in to comment.