mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 17:05:18 +00:00
2a532ede94
#11266 PS: I first attempted a serialization trick by introducing a new `appConfigResponse` and implementing `json.Marshal` to exclude these fields but it was too hacky and hard to maintain moving forward, so I'm bitting the bullet now. Happy to hear other ideas. - [X] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - ~[ ] Documented any API changes (docs/Using-Fleet/REST-API.md or docs/Contributing/API-for-contributors.md)~ - ~[ ] Documented any permissions changes~ - ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements)~ - ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for new osquery data ingestion features.~ - [X] Added/updated tests - [X] Manual QA for all new/changed functionality - ~For Orbit and Fleet Desktop changes:~ - ~[ ] Manual QA must be performed in the three main OSs, macOS, Windows and Linux.~ - ~[ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
260 lines
7.1 KiB
Go
260 lines
7.1 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"html/template"
|
|
"strings"
|
|
|
|
"github.com/fleetdm/fleet/v4/server"
|
|
authz_ctx "github.com/fleetdm/fleet/v4/server/contexts/authz"
|
|
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
|
"github.com/fleetdm/fleet/v4/server/contexts/license"
|
|
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mail"
|
|
)
|
|
|
|
// mailError is set when an error performing mail operations
|
|
type mailError struct {
|
|
message string
|
|
}
|
|
|
|
func (e mailError) Error() string {
|
|
return fmt.Sprintf("a mail error occurred: %s", e.message)
|
|
}
|
|
|
|
func (e mailError) MailError() []map[string]string {
|
|
return []map[string]string{
|
|
{
|
|
"name": "base",
|
|
"reason": e.message,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (svc *Service) NewAppConfig(ctx context.Context, p fleet.AppConfig) (*fleet.AppConfig, error) {
|
|
// skipauth: No user context yet when the app config is first created.
|
|
svc.authz.SkipAuthorization(ctx)
|
|
|
|
newConfig, err := svc.ds.NewAppConfig(ctx, &p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set up a default enroll secret
|
|
secret := svc.config.Packaging.GlobalEnrollSecret
|
|
if secret == "" {
|
|
secret, err = server.GenerateRandomText(fleet.EnrollSecretDefaultLength)
|
|
if err != nil {
|
|
return nil, ctxerr.Wrap(ctx, err, "generate enroll secret string")
|
|
}
|
|
}
|
|
secrets := []*fleet.EnrollSecret{
|
|
{
|
|
Secret: secret,
|
|
},
|
|
}
|
|
err = svc.ds.ApplyEnrollSecrets(ctx, nil, secrets)
|
|
if err != nil {
|
|
return nil, ctxerr.Wrap(ctx, err, "save enroll secret")
|
|
}
|
|
|
|
return newConfig, nil
|
|
}
|
|
|
|
func (svc *Service) sendTestEmail(ctx context.Context, config *fleet.AppConfig) error {
|
|
vc, ok := viewer.FromContext(ctx)
|
|
if !ok {
|
|
return fleet.ErrNoContext
|
|
}
|
|
|
|
var smtpSettings fleet.SMTPSettings
|
|
if config.SMTPSettings != nil {
|
|
smtpSettings = *config.SMTPSettings
|
|
}
|
|
|
|
testMail := fleet.Email{
|
|
Subject: "Hello from Fleet",
|
|
To: []string{vc.User.Email},
|
|
Mailer: &mail.SMTPTestMailer{
|
|
BaseURL: template.URL(config.ServerSettings.ServerURL + svc.config.Server.URLPrefix),
|
|
AssetURL: getAssetURL(),
|
|
},
|
|
SMTPSettings: smtpSettings,
|
|
ServerURL: config.ServerSettings.ServerURL,
|
|
}
|
|
|
|
if err := mail.Test(svc.mailService, testMail); err != nil {
|
|
return mailError{message: err.Error()}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func cleanupURL(url string) string {
|
|
return strings.TrimRight(strings.Trim(url, " \t\n"), "/")
|
|
}
|
|
|
|
func (svc *Service) License(ctx context.Context) (*fleet.LicenseInfo, error) {
|
|
if !svc.authz.IsAuthenticatedWith(ctx, authz_ctx.AuthnDeviceToken) {
|
|
if err := svc.authz.Authorize(ctx, &fleet.AppConfig{}, fleet.ActionRead); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
lic, _ := license.FromContext(ctx)
|
|
return lic, nil
|
|
}
|
|
|
|
func (svc *Service) SetupRequired(ctx context.Context) (bool, error) {
|
|
users, err := svc.ds.ListUsers(ctx, fleet.UserListOptions{ListOptions: fleet.ListOptions{Page: 0, PerPage: 1}})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if len(users) == 0 {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (svc *Service) UpdateIntervalConfig(ctx context.Context) (*fleet.UpdateIntervalConfig, error) {
|
|
return &fleet.UpdateIntervalConfig{
|
|
OSQueryDetail: svc.config.Osquery.DetailUpdateInterval,
|
|
OSQueryPolicy: svc.config.Osquery.PolicyUpdateInterval,
|
|
}, nil
|
|
}
|
|
|
|
func (svc *Service) VulnerabilitiesConfig(ctx context.Context) (*fleet.VulnerabilitiesConfig, error) {
|
|
return &fleet.VulnerabilitiesConfig{
|
|
DatabasesPath: svc.config.Vulnerabilities.DatabasesPath,
|
|
Periodicity: svc.config.Vulnerabilities.Periodicity,
|
|
CPEDatabaseURL: svc.config.Vulnerabilities.CPEDatabaseURL,
|
|
CPETranslationsURL: svc.config.Vulnerabilities.CPETranslationsURL,
|
|
CVEFeedPrefixURL: svc.config.Vulnerabilities.CVEFeedPrefixURL,
|
|
CurrentInstanceChecks: svc.config.Vulnerabilities.CurrentInstanceChecks,
|
|
DisableDataSync: svc.config.Vulnerabilities.DisableDataSync,
|
|
RecentVulnerabilityMaxAge: svc.config.Vulnerabilities.RecentVulnerabilityMaxAge,
|
|
DisableWinOSVulnerabilities: svc.config.Vulnerabilities.DisableWinOSVulnerabilities,
|
|
}, nil
|
|
}
|
|
|
|
func (svc *Service) LoggingConfig(ctx context.Context) (*fleet.Logging, error) {
|
|
conf := svc.config
|
|
logging := &fleet.Logging{
|
|
Debug: conf.Logging.Debug,
|
|
Json: conf.Logging.JSON,
|
|
}
|
|
|
|
loggings := []struct {
|
|
plugin string
|
|
target *fleet.LoggingPlugin
|
|
}{
|
|
{
|
|
plugin: conf.Osquery.StatusLogPlugin,
|
|
target: &logging.Status,
|
|
},
|
|
{
|
|
plugin: conf.Osquery.ResultLogPlugin,
|
|
target: &logging.Result,
|
|
},
|
|
}
|
|
|
|
if conf.Activity.EnableAuditLog {
|
|
loggings = append(loggings, struct {
|
|
plugin string
|
|
target *fleet.LoggingPlugin
|
|
}{
|
|
plugin: conf.Activity.AuditLogPlugin,
|
|
target: &logging.Audit,
|
|
})
|
|
}
|
|
|
|
for _, lp := range loggings {
|
|
switch lp.plugin {
|
|
case "", "filesystem":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "filesystem",
|
|
Config: fleet.FilesystemConfig{
|
|
FilesystemConfig: conf.Filesystem,
|
|
},
|
|
}
|
|
case "kinesis":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "kinesis",
|
|
Config: fleet.KinesisConfig{
|
|
Region: conf.Kinesis.Region,
|
|
StatusStream: conf.Kinesis.StatusStream,
|
|
ResultStream: conf.Kinesis.ResultStream,
|
|
AuditStream: conf.Kinesis.AuditStream,
|
|
},
|
|
}
|
|
case "firehose":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "firehose",
|
|
Config: fleet.FirehoseConfig{
|
|
Region: conf.Firehose.Region,
|
|
StatusStream: conf.Firehose.StatusStream,
|
|
ResultStream: conf.Firehose.ResultStream,
|
|
AuditStream: conf.Firehose.AuditStream,
|
|
},
|
|
}
|
|
case "lambda":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "lambda",
|
|
Config: fleet.LambdaConfig{
|
|
Region: conf.Lambda.Region,
|
|
StatusFunction: conf.Lambda.StatusFunction,
|
|
ResultFunction: conf.Lambda.ResultFunction,
|
|
AuditFunction: conf.Lambda.AuditFunction,
|
|
},
|
|
}
|
|
case "pubsub":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "pubsub",
|
|
Config: fleet.PubSubConfig{
|
|
PubSubConfig: conf.PubSub,
|
|
},
|
|
}
|
|
case "stdout":
|
|
*lp.target = fleet.LoggingPlugin{Plugin: "stdout"}
|
|
case "kafkarest":
|
|
*lp.target = fleet.LoggingPlugin{
|
|
Plugin: "kafkarest",
|
|
Config: fleet.KafkaRESTConfig{
|
|
StatusTopic: conf.KafkaREST.StatusTopic,
|
|
ResultTopic: conf.KafkaREST.ResultTopic,
|
|
AuditTopic: conf.KafkaREST.AuditTopic,
|
|
ProxyHost: conf.KafkaREST.ProxyHost,
|
|
},
|
|
}
|
|
default:
|
|
return nil, ctxerr.Errorf(ctx, "unrecognized logging plugin: %s", lp.plugin)
|
|
}
|
|
}
|
|
return logging, nil
|
|
}
|
|
|
|
func (svc *Service) EmailConfig(ctx context.Context) (*fleet.EmailConfig, error) {
|
|
if err := svc.authz.Authorize(ctx, &fleet.AppConfig{}, fleet.ActionRead); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
conf := svc.config
|
|
var email *fleet.EmailConfig
|
|
switch conf.Email.EmailBackend {
|
|
case "ses":
|
|
email = &fleet.EmailConfig{
|
|
Backend: conf.Email.EmailBackend,
|
|
Config: fleet.SESConfig{
|
|
Region: conf.SES.Region,
|
|
SourceARN: conf.SES.SourceArn,
|
|
},
|
|
}
|
|
default:
|
|
// SES is the only email provider configured as server envs/yaml file, the default implementation, SMTP, is configured via API/UI
|
|
// SMTP config gets its own dedicated section in the AppConfig response
|
|
}
|
|
|
|
return email, nil
|
|
}
|