centrifugal / centrifugo

Scalable real-time messaging server in a language-agnostic way. Self-hosted alternative to Pubnub, Pusher, Ably. Set up once and forever.
https://centrifugal.dev
Apache License 2.0
8.12k stars 581 forks source link

[feature] Revisit TLS configurations #831

Open FZambia opened 3 weeks ago

FZambia commented 3 weeks ago

Is your feature request related to a problem? Please describe.

Centrifugo has several places where it allows configuring TLS - in HTTP server, Redis connection, Kafka consumer, GRPC server and client. In the source code though we now use slightly different approach to configure TLS in various parts. I'd like to refactor the configuration a bit to use a single approach to naming and also tweak some TLS related option names. Because currently they are a bit confusing. For example, tls_cert option name should become tls_cert_pem_file. Another idea is to make TLS objects nested to detach TLS configuration objects from config key prefixes, like this:

{
  "tls": {
     "enabled": true,
     "cert_pem_file": "/tmp/centrifugo.crt",
     "key_pem_file": "/tmp/centrifugo.key"
  },
  "redis_tls": {
     "enabled": true,
     "cert_pem_file": "/tmp/redis.crt",
     "key_pem_file": "/tmp/redis.key",
     "root_ca_pem_file": "/tmp/redis_ca.pem"
  }
}

Revisited TLS configuration struct may look like this:

// TLSConfig is a common configuration for TLS.
type TLSConfig struct {
    // Enabled tells Centrifugo to enable TLS configuration.
    Enabled bool `mapstructure:"enabled" json:"enabled"`

    // Configure certificates to present to the other side of the connection.
    CertPem     string `mapstructure:"cert_pem" json:"cert_pem"`
    CertPemFile string `mapstructure:"cert_pem_file" json:"cert_pem_file"`
    KeyPem      string `mapstructure:"key_pem" json:"key_pem"`
    KeyPemFile  string `mapstructure:"key_pem_file" json:"key_pem_file"`

    // Configure the set of root certificate authorities that clients use when verifying
    // server certificates.
    RootCAPem     string `mapstructure:"root_ca_pem" json:"root_ca_pem"`
    RootCAPemFile string `mapstructure:"root_ca_pem_file" json:"root_ca_pem_file"`

    // Configure the set of root certificate authorities that servers use to verify
    // a client certificate.
    ClientCAPem     string `mapstructure:"client_ca_pem" json:"client_ca_pem"`
    ClientCAPemFile string `mapstructure:"client_ca_pem_file" json:"client_ca_pem_file"`

    InsecureSkipVerify bool   `mapstructure:"insecure_skip_verify" json:"insecure_skip_verify"`
    ServerName         string `mapstructure:"server_name" json:"server_name"`
}

Also, it seems tls options may be removed from command line flags of Centrifugo.

Finally, maybe we should natively support Base64 encoded PEM too. Like:

CertPemB64     string `mapstructure:"cert_pem_b64" json:"cert_pem_b64"`

Describe the solution you'd like.

What would the feature look like? How would it work? How would it change the API?

Look at all places where TLS may be configured and use revisited common configuration strategy. This should make configuration cleaner overall.

swagftw commented 1 week ago

For any one looking for insecureSkipVerify flag, this issue will add it.

FZambia commented 1 week ago

Revised Go struct to configure TLS:

// TLSConfig is a common configuration for TLS.
// It allows to configure TLS settings using different sources. The order sources are used is the following:
// 1. File to PEM
// 2. Base64 encoded PEM
// 3. Raw PEM
// It's up to the user to only use a single source of configured values. I.e. if both file and raw PEM are set
// the file will be used and raw PEM will be just ignored.
type TLSConfig struct {
    // Enabled turns on using TLS.
    Enabled bool `mapstructure:"enabled" json:"enabled"`

    // CertPem is a certificate in PEM format.
    CertPem string `mapstructure:"cert_pem" json:"cert_pem" envconfig:"cert_pem"`
    // CertPemB64 is a certificate in base64 encoded PEM format.
    CertPemB64 string `mapstructure:"cert_pem_b64" json:"cert_pem_b64" envconfig:"cert_pem_b64"`
    // CertPemFile is a path to a file with certificate in PEM format.
    CertPemFile string `mapstructure:"cert_pem_file" json:"cert_pem_file" envconfig:"cert_pem_file"`

    // KeyPem is a key in PEM format.
    KeyPem string `mapstructure:"key_pem" json:"key_pem" envconfig:"key_pem"`
    // KeyPemB64 is a key in base64 encoded PEM format.
    KeyPemB64 string `mapstructure:"key_pem_b64" json:"key_pem_b64" envconfig:"key_pem_b64"`
    // KeyPemFile is a path to a file with key in PEM format.
    KeyPemFile string `mapstructure:"key_pem_file" json:"key_pem_file" envconfig:"key_pem_file"`

    // ServerCAPem is a server root CA certificate in PEM format.
    // The client uses this certificate to verify the server's certificate during the TLS handshake.
    ServerCAPem string `mapstructure:"server_ca_pem" json:"server_ca_pem" envconfig:"server_ca_pem"`
    // ServerCAPemB64 is a server root CA certificate in base64 encoded PEM format.
    ServerCAPemB64 string `mapstructure:"server_ca_pem_b64" json:"server_ca_pem_b64" envconfig:"server_ca_pem_b64"`
    // ServerCAPemFile is a path to a file with server root CA certificate in PEM format.
    ServerCAPemFile string `mapstructure:"server_ca_pem_file" json:"server_ca_pem_file" envconfig:"server_ca_pem_file"`

    // ClientCAPem is a client CA certificate in PEM format.
    // The server uses this certificate to verify the client's certificate during the TLS handshake.
    ClientCAPem string `mapstructure:"client_ca_pem" json:"client_ca_pem" envconfig:"client_ca_pem"`
    // ClientCAPemB64 is a client CA certificate in base64 encoded PEM format.
    ClientCAPemB64 string `mapstructure:"client_ca_pem_b64" json:"client_ca_pem_b64" envconfig:"client_ca_pem_b64"`
    // ClientCAPemFile is a path to a file with client CA certificate in PEM format.
    ClientCAPemFile string `mapstructure:"client_ca_pem_file" json:"client_ca_pem_file" envconfig:"client_ca_pem_file"`

    // InsecureSkipVerify turns off server certificate verification.
    InsecureSkipVerify bool `mapstructure:"insecure_skip_verify" json:"insecure_skip_verify" envconfig:"insecure_skip_verify"`
    // ServerName is used to verify the hostname on the returned certificates.
    ServerName string `mapstructure:"server_name" json:"server_name" envconfig:"server_name"`
}

Note: