create crowdsec group for metabase and crowdsec.db (#606)

This commit is contained in:
AlteredCoder 2021-02-10 09:23:33 +01:00 committed by GitHub
parent 260332c726
commit dae4458a6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 66 deletions

View file

@ -3,7 +3,10 @@ package main
import (
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"strconv"
"github.com/AlecAivazis/survey/v2"
"github.com/crowdsecurity/crowdsec/pkg/metabase"
@ -24,6 +27,7 @@ var (
metabaseListenAddress = "127.0.0.1"
metabaseListenPort = "3000"
metabaseContainerID = "/crowdsec-metabase"
crowdsecGroup = "crowdsec"
forceYes bool
@ -72,7 +76,48 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
if metabasePassword == "" {
metabasePassword = generatePassword(16)
}
mb, err := metabase.SetupMetabase(csConfig.API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDbPath)
var answer bool
groupExist := false
dockerGroup, err := user.LookupGroup(crowdsecGroup)
if err == nil {
groupExist = true
}
if !forceYes && !groupExist {
prompt := &survey.Confirm{
Message: fmt.Sprintf("For metabase docker to be able to access SQLite file we need to add a new group called '%s' to the system, is it ok for you ?", crowdsecGroup),
Default: true,
}
if err := survey.AskOne(prompt, &answer); err != nil {
log.Fatalf("unable to ask to force: %s", err)
}
}
if !answer && !forceYes && !groupExist {
log.Fatalf("unable to continue without creating '%s' group", crowdsecGroup)
}
if !groupExist {
groupAddCmd, err := exec.LookPath("groupadd")
if err != nil {
log.Fatalf("unable to find 'groupadd' command, can't continue")
}
groupAdd := &exec.Cmd{Path: groupAddCmd, Args: []string{groupAddCmd, crowdsecGroup}}
if err := groupAdd.Run(); err != nil {
log.Fatalf("unable to add group '%s': %s", dockerGroup, err)
}
dockerGroup, err = user.LookupGroup(crowdsecGroup)
if err != nil {
log.Fatalf("unable to lookup '%s' group: %+v", dockerGroup, err)
}
}
intID, err := strconv.Atoi(dockerGroup.Gid)
if err != nil {
log.Fatalf("unable to convert group ID to int: %s", err)
}
if err := os.Chown(csConfig.DbConfig.DbPath, 0, intID); err != nil {
log.Fatalf("unable to chown sqlite db file '%s': %s", csConfig.DbConfig.DbPath, err)
}
mb, err := metabase.SetupMetabase(csConfig.API.Server.DbConfig, metabaseListenAddress, metabaseListenPort, metabaseUser, metabasePassword, metabaseDbPath, dockerGroup.Gid)
if err != nil {
log.Fatalf(err.Error())
}
@ -92,6 +137,7 @@ cscli dashboard setup -l 0.0.0.0 -p 443 --password <password>
cmdDashSetup.Flags().StringVarP(&metabaseDbPath, "dir", "d", "", "Shared directory with metabase container.")
cmdDashSetup.Flags().StringVarP(&metabaseListenAddress, "listen", "l", metabaseListenAddress, "Listen address of container")
cmdDashSetup.Flags().StringVarP(&metabaseListenPort, "port", "p", metabaseListenPort, "Listen port of container")
cmdDashSetup.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes")
//cmdDashSetup.Flags().StringVarP(&metabaseUser, "user", "u", "crowdsec@crowdsec.net", "metabase user")
cmdDashSetup.Flags().StringVar(&metabasePassword, "password", "", "metabase password")
@ -149,34 +195,44 @@ cscli dashboard remove --force
log.Fatalf("unable to ask to force: %s", err)
}
}
if answer {
if metabase.IsContainerExist(metabaseContainerID) {
log.Debugf("Stopping container %s", metabaseContainerID)
if err := metabase.StopContainer(metabaseContainerID); err != nil {
log.Warningf("unable to stop container '%s': %s", metabaseContainerID, err)
}
dockerGroup, err := user.LookupGroup(crowdsecGroup)
if err == nil { // if group exist, remove it
groupDelCmd, err := exec.LookPath("groupdel")
if err != nil {
log.Fatalf("unable to find 'groupdel' command, can't continue")
}
groupDel := &exec.Cmd{Path: groupDelCmd, Args: []string{groupDelCmd, crowdsecGroup}}
if err := groupDel.Run(); err != nil {
log.Errorf("unable to delete group '%s': %s", dockerGroup, err)
}
}
log.Debugf("Removing container %s", metabaseContainerID)
if err := metabase.RemoveContainer(metabaseContainerID); err != nil {
log.Warningf("unable to remove container '%s': %s", metabaseContainerID, err)
}
log.Infof("container %s stopped & removed", metabaseContainerID)
}
log.Debugf("Removing database %s", csConfig.ConfigPaths.DataDir)
log.Debugf("Removing metabase db %s", csConfig.ConfigPaths.DataDir)
if err := metabase.RemoveDatabase(csConfig.ConfigPaths.DataDir); err != nil {
log.Warningf("failed to remove metabase internal db : %s", err)
}
if force {
log.Debugf("Removing image %s", metabaseImage)
if err := metabase.RemoveImageContainer(metabaseImage); err != nil {
log.Warningf("Failed to remove metabase container %s : %s", metabaseImage, err)
if err := metabase.RemoveImageContainer(); err != nil {
log.Fatalf("removing docker image: %s", err)
}
}
}
},
}
cmdDashRemove.Flags().BoolVarP(&force, "force", "f", false, "Force remove : stop the container if running and remove.")
cmdDashRemove.Flags().BoolVarP(&force, "force", "f", false, "Remove also the metabase image")
cmdDashRemove.Flags().BoolVarP(&forceYes, "yes", "y", false, "force yes")
cmdDashboard.AddCommand(cmdDashRemove)

View file

@ -42,7 +42,7 @@ func NewClient(config *csconfig.DatabaseCfg) (*Client, error) {
return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath)
}
} else { /*ensure file perms*/
if err := os.Chmod(config.DbPath, 0600); err != nil {
if err := os.Chmod(config.DbPath, 0660); err != nil {
return &Client{}, fmt.Errorf("unable to set perms on %s: %v", config.DbPath, err)
}
}

View file

@ -16,29 +16,31 @@ import (
)
type Container struct {
ListenAddr string
ListenPort string
SharedFolder string
Image string
Name string
ID string
CLI *client.Client
MBDBUri string
ListenAddr string
ListenPort string
SharedFolder string
Image string
Name string
ID string
CLI *client.Client
MBDBUri string
DockerGroupID string
}
func NewContainer(listenAddr string, listenPort string, sharedFolder string, name string, image string, mbDBURI string) (*Container, error) {
func NewContainer(listenAddr string, listenPort string, sharedFolder string, name string, image string, mbDBURI string, dockerGroupID string) (*Container, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return nil, fmt.Errorf("failed to create docker client : %s", err)
}
return &Container{
ListenAddr: listenAddr,
ListenPort: listenPort,
SharedFolder: sharedFolder,
Image: image,
Name: name,
CLI: cli,
MBDBUri: mbDBURI,
ListenAddr: listenAddr,
ListenPort: listenPort,
SharedFolder: sharedFolder,
Image: image,
Name: name,
CLI: cli,
MBDBUri: mbDBURI,
DockerGroupID: dockerGroupID,
}, nil
}
@ -84,12 +86,12 @@ func (c *Container) Create() error {
env = append(env, c.MBDBUri)
}
env = append(env, fmt.Sprintf("MGID=%s", c.DockerGroupID))
dockerConfig := &container.Config{
Image: c.Image,
Tty: true,
Env: env,
}
os := runtime.GOOS
switch os {
case "linux":
@ -158,15 +160,15 @@ func RemoveContainer(name string) error {
return nil
}
func RemoveImageContainer(image string) error {
func RemoveImageContainer() error {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return fmt.Errorf("failed to create docker client : %s", err)
}
ctx := context.Background()
log.Printf("Removing docker metabase %s", image)
if err := cli.ContainerRemove(ctx, image, types.ContainerRemoveOptions{}); err != nil {
return fmt.Errorf("failed remove container %s : %s", image, err)
log.Printf("Removing docker image '%s'", metabaseImage)
if _, err := cli.ImageRemove(ctx, metabaseImage, types.ImageRemoveOptions{}); err != nil {
return fmt.Errorf("failed remove image container %s : %s", metabaseImage, err)
}
return nil
}

View file

@ -28,13 +28,14 @@ type Metabase struct {
}
type Config struct {
Database *csconfig.DatabaseCfg `yaml:"database"`
ListenAddr string `yaml:"listen_addr"`
ListenPort string `yaml:"listen_port"`
ListenURL string `yaml:"listen_url"`
Username string `yaml:"username"`
Password string `yaml:"password"`
DBPath string `yaml:"metabase_db_path"`
Database *csconfig.DatabaseCfg `yaml:"database"`
ListenAddr string `yaml:"listen_addr"`
ListenPort string `yaml:"listen_port"`
ListenURL string `yaml:"listen_url"`
Username string `yaml:"username"`
Password string `yaml:"password"`
DBPath string `yaml:"metabase_db_path"`
DockerGroupID string `yaml:"-"`
}
var (
@ -70,7 +71,7 @@ func (m *Metabase) Init() error {
}
m.Database, err = NewDatabase(m.Config.Database, m.Client, remoteDBAddr)
m.Container, err = NewContainer(m.Config.ListenAddr, m.Config.ListenPort, m.Config.DBPath, containerName, metabaseImage, DBConnectionURI)
m.Container, err = NewContainer(m.Config.ListenAddr, m.Config.ListenPort, m.Config.DBPath, containerName, metabaseImage, DBConnectionURI, m.Config.DockerGroupID)
if err != nil {
return errors.Wrap(err, "container init")
}
@ -123,16 +124,17 @@ func (m *Metabase) LoadConfig(configPath string) error {
}
func SetupMetabase(dbConfig *csconfig.DatabaseCfg, listenAddr string, listenPort string, username string, password string, mbDBPath string) (*Metabase, error) {
func SetupMetabase(dbConfig *csconfig.DatabaseCfg, listenAddr string, listenPort string, username string, password string, mbDBPath string, dockerGroupID string) (*Metabase, error) {
metabase := &Metabase{
Config: &Config{
Database: dbConfig,
ListenAddr: listenAddr,
ListenPort: listenPort,
Username: username,
Password: password,
ListenURL: fmt.Sprintf("http://%s:%s", listenAddr, listenPort),
DBPath: mbDBPath,
Database: dbConfig,
ListenAddr: listenAddr,
ListenPort: listenPort,
Username: username,
Password: password,
ListenURL: fmt.Sprintf("http://%s:%s", listenAddr, listenPort),
DBPath: mbDBPath,
DockerGroupID: dockerGroupID,
},
}
if err := metabase.Init(); err != nil {

View file

@ -302,47 +302,44 @@ check_cs_version () {
NEW_PATCH_VERSION=$(echo $NEW_CS_VERSION | cut -d'.' -f3)
if [[ $NEW_MAJOR_VERSION -gt $CURRENT_MAJOR_VERSION ]]; then
log_warn "new version ($NEW_CS_VERSION) is a major, you need to follow documentation to upgrade !"
echo ""
echo "Please follow : https://docs.crowdsec.net/Crowdsec/v1/migration/"
if [[ ${FORCE_MODE} == "false" ]]; then
log_warn "new version ($NEW_CS_VERSION) is a major, you need to follow documentation to upgrade !"
echo ""
echo "Please follow : https://docs.crowdsec.net/Crowdsec/v1/migration/"
exit 1
fi
elif [[ $NEW_MINOR_VERSION -gt $CURRENT_MINOR_VERSION ]] ; then
log_warn "new version ($NEW_CS_VERSION) is a minor upgrade !"
if [[ $ACTION != "upgrade" ]] ; then
echo ""
echo "We recommand to upgrade with : sudo ./wizard.sh --upgrade "
echo "If you want to $ACTION anyway, please use '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
if [[ ${FORCE_MODE} == "false" ]]; then
echo ""
echo "We recommand to upgrade with : sudo ./wizard.sh --upgrade "
echo "If you want to $ACTION anyway, please use '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
exit 1
fi
fi
elif [[ $NEW_PATCH_VERSION -gt $CURRENT_PATCH_VERSION ]] ; then
log_warn "new version ($NEW_CS_VERSION) is a patch !"
if [[ $ACTION != "binupgrade" ]] ; then
echo ""
echo "We recommand to upgrade binaries only : sudo ./wizard.sh --binupgrade "
echo "If you want to $ACTION anyway, please use '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
if [[ ${FORCE_MODE} == "false" ]]; then
echo ""
echo "We recommand to upgrade binaries only : sudo ./wizard.sh --binupgrade "
echo "If you want to $ACTION anyway, please use '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
exit 1
fi
fi
elif [[ $NEW_MINOR_VERSION -eq $CURRENT_MINOR_VERSION ]]; then
log_warn "new version ($NEW_CS_VERSION) is same as current version ($CURRENT_CS_VERSION) !"
echo ""
echo "We recommand to $ACTION only if it's an higher version. "
echo "If it's an RC version (vX.X.X-rc) you can upgrade it using '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
if [[ ${FORCE_MODE} == "false" ]]; then
echo ""
echo "We recommand to $ACTION only if it's an higher version. "
echo "If it's an RC version (vX.X.X-rc) you can upgrade it using '--force'."
echo ""
echo "Run : sudo ./wizard.sh --$ACTION --force"
exit 1
fi
fi