mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 00:09:40 +02:00
feat(server): use https by default (#5315) [EE-332]
This commit is contained in:
parent
3257cb1e28
commit
11d555bbd6
32 changed files with 1160 additions and 319 deletions
170
api/internal/ssl/ssl.go
Normal file
170
api/internal/ssl/ssl.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
package ssl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/portainer/libcrypto"
|
||||
portainer "github.com/portainer/portainer/api"
|
||||
)
|
||||
|
||||
// Service represents a service to manage SSL certificates
|
||||
type Service struct {
|
||||
fileService portainer.FileService
|
||||
dataStore portainer.DataStore
|
||||
rawCert *tls.Certificate
|
||||
shutdownTrigger context.CancelFunc
|
||||
}
|
||||
|
||||
// NewService returns a pointer to a new Service
|
||||
func NewService(fileService portainer.FileService, dataStore portainer.DataStore, shutdownTrigger context.CancelFunc) *Service {
|
||||
return &Service{
|
||||
fileService: fileService,
|
||||
dataStore: dataStore,
|
||||
shutdownTrigger: shutdownTrigger,
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes the service
|
||||
func (service *Service) Init(host, certPath, keyPath string) error {
|
||||
settings, err := service.GetSSLSettings()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed fetching ssl settings")
|
||||
}
|
||||
|
||||
// certificates already exist
|
||||
if settings.CertPath != "" && settings.KeyPath != "" {
|
||||
err := service.cacheCertificate(settings.CertPath, settings.KeyPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// continue if certs don't exist
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
pathSupplied := certPath != "" && keyPath != ""
|
||||
if pathSupplied {
|
||||
newCertPath, newKeyPath, err := service.fileService.CopySSLCertPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed copying supplied certs")
|
||||
}
|
||||
|
||||
return service.cacheInfo(newCertPath, newKeyPath, false)
|
||||
}
|
||||
|
||||
// path not supplied and certificates doesn't exist - generate self signed
|
||||
certPath, keyPath = service.fileService.GetDefaultSSLCertsPath()
|
||||
|
||||
err = service.generateSelfSignedCertificates(host, certPath, keyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed generating self signed certs")
|
||||
}
|
||||
|
||||
return service.cacheInfo(certPath, keyPath, true)
|
||||
|
||||
}
|
||||
|
||||
// GetRawCertificate gets the raw certificate
|
||||
func (service *Service) GetRawCertificate() *tls.Certificate {
|
||||
return service.rawCert
|
||||
}
|
||||
|
||||
// GetSSLSettings gets the certificate info
|
||||
func (service *Service) GetSSLSettings() (*portainer.SSLSettings, error) {
|
||||
return service.dataStore.SSLSettings().Settings()
|
||||
}
|
||||
|
||||
// SetCertificates sets the certificates
|
||||
func (service *Service) SetCertificates(certData, keyData []byte) error {
|
||||
if len(certData) == 0 || len(keyData) == 0 {
|
||||
return errors.New("missing certificate files")
|
||||
}
|
||||
|
||||
_, err := tls.X509KeyPair(certData, keyData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certPath, keyPath, err := service.fileService.StoreSSLCertPair(certData, keyData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service.cacheInfo(certPath, keyPath, false)
|
||||
|
||||
service.shutdownTrigger()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) SetHTTPEnabled(httpEnabled bool) error {
|
||||
settings, err := service.dataStore.SSLSettings().Settings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if settings.HTTPEnabled == httpEnabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
settings.HTTPEnabled = httpEnabled
|
||||
|
||||
err = service.dataStore.SSLSettings().UpdateSettings(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service.shutdownTrigger()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) cacheCertificate(certPath, keyPath string) error {
|
||||
rawCert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service.rawCert = &rawCert
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) cacheInfo(certPath, keyPath string, selfSigned bool) error {
|
||||
err := service.cacheCertificate(certPath, keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings, err := service.dataStore.SSLSettings().Settings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
settings.CertPath = certPath
|
||||
settings.KeyPath = keyPath
|
||||
settings.SelfSigned = selfSigned
|
||||
|
||||
err = service.dataStore.SSLSettings().UpdateSettings(settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) generateSelfSignedCertificates(ip, certPath, keyPath string) error {
|
||||
if ip == "" {
|
||||
return errors.New("host can't be empty")
|
||||
}
|
||||
|
||||
log.Printf("[INFO] [internal,ssl] [message: no cert files found, generating self signed ssl certificates]")
|
||||
return libcrypto.GenerateCertsForHost("localhost", ip, certPath, keyPath, time.Now().AddDate(5, 0, 0))
|
||||
}
|
|
@ -17,6 +17,7 @@ type datastore struct {
|
|||
registry portainer.RegistryService
|
||||
resourceControl portainer.ResourceControlService
|
||||
role portainer.RoleService
|
||||
sslSettings portainer.SSLSettingsService
|
||||
settings portainer.SettingsService
|
||||
stack portainer.StackService
|
||||
tag portainer.TagService
|
||||
|
@ -47,6 +48,7 @@ func (d *datastore) Registry() portainer.RegistryService { retur
|
|||
func (d *datastore) ResourceControl() portainer.ResourceControlService { return d.resourceControl }
|
||||
func (d *datastore) Role() portainer.RoleService { return d.role }
|
||||
func (d *datastore) Settings() portainer.SettingsService { return d.settings }
|
||||
func (d *datastore) SSLSettings() portainer.SSLSettingsService { return d.sslSettings }
|
||||
func (d *datastore) Stack() portainer.StackService { return d.stack }
|
||||
func (d *datastore) Tag() portainer.TagService { return d.tag }
|
||||
func (d *datastore) TeamMembership() portainer.TeamMembershipService { return d.teamMembership }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue