Skip to content
Closed
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
19 changes: 17 additions & 2 deletions components/gitpod-db/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,40 @@ import { ConnectionConfig } from "mysql";
export class Config {
get dbConfig(): DatabaseConfig {
// defaults to be used only in tests
const dbSetup = {
const dbSetup: DatabaseConfig = {
host: process.env.DB_HOST || "localhost",
port: getEnvVarParsed("DB_PORT", Number.parseInt, "3306"),
username: process.env.DB_USERNAME || "gitpod",
password: process.env.DB_PASSWORD || "test",
database: process.env.DB_NAME || "gitpod",
};

if (process.env.DB_CUSTOM_CA_CERT) {
dbSetup.ssl = {
ca: process.env.DB_CUSTOM_CA_CERT,
};
}

log.info(`Using DB: ${dbSetup.host}:${dbSetup.port}/${dbSetup.database}`);

return dbSetup;
}

get mysqlConfig(): ConnectionConfig {
const dbConfig = this.dbConfig;
return {
const mysqlConfig: ConnectionConfig = {
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
};
if (dbConfig.ssl?.ca) {
mysqlConfig.ssl = {
ca: dbConfig.ssl.ca,
};
}
return mysqlConfig;
}

get dbEncryptionKeys(): string {
Expand All @@ -48,4 +60,7 @@ export interface DatabaseConfig {
database?: string;
username?: string;
password?: string;
ssl?: {
ca?: string;
};
}
2 changes: 1 addition & 1 deletion components/gitpod-db/src/wait-for-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as mysql from "mysql";

const retryPeriod = 5000; // [ms]
const totalAttempts = 30;
const connCfg = {
const connCfg: mysql.ConnectionConfig = {
...new Config().mysqlConfig,
timeout: retryPeriod,
};
Expand Down
32 changes: 26 additions & 6 deletions components/usage/pkg/db/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@
package db

import (
"crypto/tls"
"crypto/x509"
"fmt"
"time"

"github.com/gitpod-io/gitpod/common-go/log"
driver_mysql "github.com/go-sql-driver/mysql"
"github.com/sirupsen/logrus"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"time"
)

type ConnectionParams struct {
User string
Password string
Host string
Database string
User string
Password string
Host string
Database string
CustomCACert string
}

func Connect(p ConnectionParams) (*gorm.DB, error) {
loc, err := time.LoadLocation("UTC")
if err != nil {
return nil, fmt.Errorf("failed to load UT location: %w", err)
return nil, fmt.Errorf("Failed to load UT location: %w", err)
}
cfg := driver_mysql.Config{
User: p.User,
Expand All @@ -38,6 +42,22 @@ func Connect(p ConnectionParams) (*gorm.DB, error) {
ParseTime: true,
}

if p.CustomCACert != "" {
rootCertPool := x509.NewCertPool()
if ok := rootCertPool.AppendCertsFromPEM([]byte(p.CustomCACert)); !ok {
log.Fatal("Failed to append custom DB CA cert.")
}

tlsConfigName := "custom"
err = driver_mysql.RegisterTLSConfig(tlsConfigName, &tls.Config{
RootCAs: rootCertPool,
})
if err != nil {
return nil, fmt.Errorf("Failed to register custom DB CA cert: %w", err)
}
cfg.TLSConfig = tlsConfigName
}

// refer to https://github.com/go-sql-driver/mysql#dsn-data-source-name for details
return gorm.Open(mysql.Open(cfg.FormatDSN()), &gorm.Config{
Logger: logger.New(log.Log, logger.Config{
Expand Down
9 changes: 5 additions & 4 deletions components/usage/pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ func Start(cfg Config, version string) error {
log.WithField("config", cfg).Info("Starting usage component.")

conn, err := db.Connect(db.ConnectionParams{
User: os.Getenv("DB_USERNAME"),
Password: os.Getenv("DB_PASSWORD"),
Host: net.JoinHostPort(os.Getenv("DB_HOST"), os.Getenv("DB_PORT")),
Database: "gitpod",
User: os.Getenv("DB_USERNAME"),
Password: os.Getenv("DB_PASSWORD"),
Host: net.JoinHostPort(os.Getenv("DB_HOST"), os.Getenv("DB_PORT")),
Database: "gitpod",
CustomCACert: os.Getenv("DB_CUSTOM_CA_CERT"),
})
if err != nil {
return fmt.Errorf("failed to establish database connection: %w", err)
Expand Down
11 changes: 11 additions & 0 deletions install/installer/pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,17 @@ func DatabaseEnv(cfg *config.Config) (res []corev1.EnvVar) {
},
)

if cfg.Database.SSL != nil && cfg.Database.SSL.CustomCA != nil {
secretRef = corev1.LocalObjectReference{Name: cfg.Database.SSL.CustomCA.Name}
envvars = append(envvars, corev1.EnvVar{
Name: DBCustomCaCertEnvVarName,
ValueFrom: &corev1.EnvVarSource{SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: secretRef,
Key: DBCustomCaFileName,
}},
})
}

return envvars
}

Expand Down
4 changes: 4 additions & 0 deletions install/installer/pkg/common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const (
ImageBuilderComponent = "image-builder-mk3"
ImageBuilderRPCPort = 8080
DebugNodePort = 9229
DBCustomCaCertEnvVarName = "DB_CUSTOM_CA_CERT"
DBCustomCaFileName = "ca.crt"
DBCustomCaBasePath = "/"
DBCustomCaPath = DBCustomCaBasePath + DBCustomCaFileName

AnnotationConfigChecksum = "gitpod.io/checksum_config"
)
Expand Down
11 changes: 6 additions & 5 deletions install/installer/pkg/components/database/init/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
package init

const (
Component = "dbinit"
dbSessionsImage = "library/mysql"
dbSessionsTag = "5.7.34"
initScriptDir = "files"
sqlInitScripts = "db-init-scripts"
Component = "dbinit"
dbSessionsImage = "library/mysql"
dbSessionsTag = "5.7.34"
initScriptDir = "files"
sqlInitScripts = "db-init-scripts"
customCaMountName = "db-custom-ca"
)
44 changes: 32 additions & 12 deletions install/installer/pkg/components/database/init/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,35 @@ func job(ctx *common.RenderContext) ([]runtime.Object, error) {
Annotations: common.CustomizeAnnotation(ctx, Component, common.TypeMetaBatchJob),
}

volumes := []corev1.Volume{{
Name: sqlInitScripts,
VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: sqlInitScripts},
}},
}}
volumeMounts := []corev1.VolumeMount{{
Name: sqlInitScripts,
MountPath: "/db-init-scripts",
ReadOnly: true,
}}

// We already have CA loaded at common.DBCustomCaCertEnvVarName, but mysql cli needs a file here, so we mount it like as one.
sslOptions := ""
if ctx.Config.Database.SSL != nil && ctx.Config.Database.SSL.CustomCA != nil {
volumes = append(volumes, corev1.Volume{
Name: customCaMountName,
VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{
SecretName: ctx.Config.Database.SSL.CustomCA.Name,
}},
})
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: customCaMountName,
MountPath: common.DBCustomCaBasePath,
ReadOnly: true,
})
sslOptions = fmt.Sprintf(" --ssl-mode=VERIFY_IDENTITY --ssl-ca=%s ", common.DBCustomCaPath)
}

return []runtime.Object{&batchv1.Job{
TypeMeta: common.TypeMetaBatchJob,
ObjectMeta: objectMeta,
Expand All @@ -43,12 +72,7 @@ func job(ctx *common.RenderContext) ([]runtime.Object, error) {
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: Component,
EnableServiceLinks: pointer.Bool(false),
Volumes: []corev1.Volume{{
Name: sqlInitScripts,
VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{Name: sqlInitScripts},
}},
}},
Volumes: volumes,
// The init container is designed to emulate Helm hooks
InitContainers: []corev1.Container{*common.DatabaseWaiterContainer(ctx)},
Containers: []corev1.Container{{
Expand All @@ -61,13 +85,9 @@ func job(ctx *common.RenderContext) ([]runtime.Object, error) {
Command: []string{
"sh",
"-c",
"mysql -h $DB_HOST --port $DB_PORT -u $DB_USERNAME -p$DB_PASSWORD < /db-init-scripts/init.sql",
fmt.Sprintf("mysql -h $DB_HOST --port $DB_PORT -u $DB_USERNAME -p$DB_PASSWORD %s< /db-init-scripts/init.sql", sslOptions),
},
VolumeMounts: []corev1.VolumeMount{{
Name: sqlInitScripts,
MountPath: "/db-init-scripts",
ReadOnly: true,
}},
VolumeMounts: volumeMounts,
}},
},
},
Expand Down
5 changes: 5 additions & 0 deletions install/installer/pkg/config/v1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ type Database struct {
InCluster *bool `json:"inCluster,omitempty"`
External *DatabaseExternal `json:"external,omitempty"`
CloudSQL *DatabaseCloudSQL `json:"cloudSQL,omitempty"`
SSL *SSLOptions `json:"ssl,omitempty"`
}

type DatabaseExternal struct {
Expand All @@ -230,6 +231,10 @@ type DatabaseCloudSQL struct {
Instance string `json:"instance" validate:"required"`
}

type SSLOptions struct {
CustomCA *ObjectRef `json:"customCa,omitempty"`
}

type ObjectStorage struct {
InCluster *bool `json:"inCluster,omitempty"`
S3 *ObjectStorageS3 `json:"s3,omitempty"`
Expand Down