create crowdsec group for metabase and crowdsec.db (#606)
This commit is contained in:
parent
260332c726
commit
dae4458a6f
5 changed files with 123 additions and 66 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
39
wizard.sh
39
wizard.sh
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue