Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions veinmind-runner/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import (
"context"
"encoding/json"
"errors"
"github.com/chaitin/libveinmind/go"
"os"
"path"
"path/filepath"
"strings"

api "github.com/chaitin/libveinmind/go"
"github.com/chaitin/libveinmind/go/cmd"
"github.com/chaitin/libveinmind/go/containerd"
"github.com/chaitin/libveinmind/go/docker"
Expand All @@ -19,10 +24,6 @@ import (
"github.com/chaitin/veinmind-tools/veinmind-runner/pkg/reporter"
"github.com/distribution/distribution/reference"
"github.com/spf13/cobra"
"os"
"path"
"path/filepath"
"strings"
)

const (
Expand Down Expand Up @@ -160,6 +161,35 @@ var authCmd = &cmd.Command{
return server.Run()
},
}

var webhookCmd = &cmd.Command{
Use: "webhook",
Short: "webhook for harbor",
RunE: func(cmd *cobra.Command, args []string) error {
path, err := cmd.Flags().GetString("config")
if err != nil {
return err
}

config, err := authz.NewHarborWebhookConfig(path)
if err != nil {
return err
}

options := []authz.ServerOption{
authz.WithHarborPolicy(config.Policies...),
authz.WithAuthLog(config.Log.AuthZLogPath),
authz.WithPluginLog(config.Log.PluginLogPath),
authz.WithPort(config.Port.Port),
authz.WithPassword(config.Password.Password),
authz.WithAuthInfo(config.DockerAuth),
authz.WithMailServer(config.MailConf),
}

server := authz.NewHarborWebhook(options...)
return server.Run()
},
}
var listCmd = &cmd.Command{
Use: "list",
Short: "list relevant information",
Expand Down Expand Up @@ -226,7 +256,7 @@ var scanRegistryCmd = &cmd.Command{
if config == "" {
c, err = commonRuntime.NewDockerClient()
} else {
c, err = commonRuntime.NewDockerClient(commonRuntime.WithAuth(config))
c, err = commonRuntime.NewDockerClient(commonRuntime.WithAuthFromPath(config))
}
if err != nil {
return err
Expand Down Expand Up @@ -467,6 +497,8 @@ func init() {
rootCmd.AddCommand(scanRegistryCmd)
rootCmd.AddCommand(authCmd)
authCmd.Flags().StringP("config", "c", "", "authz config path")
rootCmd.AddCommand(webhookCmd)
webhookCmd.Flags().StringP("config", "c", "", "webhook config path")
rootCmd.AddCommand(listCmd)
rootCmd.PersistentFlags().IntP("exit-code", "e", 0, "exit-code when veinmind-runner find security issues")
listCmd.AddCommand(listPluginCmd)
Expand Down
31 changes: 31 additions & 0 deletions veinmind-runner/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[log]
plugin_log_path = "plugin.log"
auth_log_path = "auth.log"

[port]
port = "8081"

[webhook_password]
password = "asdqwe123"

[[policies]]
action = "PUSH_ARTIFACT"
enabled_plugins = ["veinmind-weakpass"]
plugin_params = ["veinmind-weakpass:scan.serviceName=ssh"]
risk_level_filter = ["High"]
block = true
alert = true
send_mail = true

[docker_auth]
registry = "10.9.33.98"
username = "admin"
password = "asdqwe123"

[mail_conf]
host = "smtp.qq.com"
port = 465
username = "369212851@qq.com"
password = "test"
send_to = ["220205328@seu.edu.cn"]

4 changes: 3 additions & 1 deletion veinmind-runner/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ go 1.16
require (
github.com/BurntSushi/toml v0.4.1
github.com/chaitin/libveinmind v1.1.1
github.com/chaitin/veinmind-common-go v1.0.5
github.com/chaitin/veinmind-common-go v1.1.0
github.com/distribution/distribution v2.8.1+incompatible
github.com/docker/docker v20.10.17+incompatible
github.com/gin-gonic/gin v1.8.1
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.4.0
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1
gotest.tools/v3 v3.1.0 // indirect
)

Expand Down
8 changes: 6 additions & 2 deletions veinmind-runner/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chaitin/libveinmind v1.1.1 h1:DoMJXAjw3xzOHcrAiBBQpbqudsumw5pGfRQko6f6USc=
github.com/chaitin/libveinmind v1.1.1/go.mod h1:bUUjhkyZyZ9sTetpm5rOfj5TU3hr5moE3VQM+IgHrbw=
github.com/chaitin/veinmind-common-go v1.0.5 h1:OA8c9IDMPGXUBQksiFck6tx5eEtfDz9LB1+FcmaSMDY=
github.com/chaitin/veinmind-common-go v1.0.5/go.mod h1:pmtVj6duS6B3spaBPhMMXOZOzDyyABtcEIQEF4KpZaI=
github.com/chaitin/veinmind-common-go v1.1.0 h1:YKE+KBVyP48IBKFf4dH5Ve8ayHz8rQ8S07iFPF8z60U=
github.com/chaitin/veinmind-common-go v1.1.0/go.mod h1:Ap6KTM2qqKv+8tLeb38pX9DFWt/P8/1gmCO2b9tjNZo=
github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
Expand Down Expand Up @@ -2047,6 +2047,8 @@ google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscL
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand All @@ -2069,6 +2071,8 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1 h1:d4KQkxAaAiRY2h5Zqis161Pv91A37uZyJOx73duwUwM=
Expand Down
39 changes: 39 additions & 0 deletions veinmind-runner/pkg/authz/action/harbor_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package action

import (
"errors"

"github.com/chaitin/libveinmind/go/plugin/log"
"github.com/chaitin/veinmind-common-go/pkg/auth"
"github.com/chaitin/veinmind-common-go/runtime"
"github.com/gin-gonic/gin"
)

// get secrect from Authorization field and check
func CheckPassword(c *gin.Context, password string) error {
if password == "" {
return nil
}
if c.Request.Header.Get("Authorization") == password {
return nil
}
return errors.New("error passowrd")
}

// download relevant images
func GetImagesFromHarbor(authentity auth.Auth, imageNames []string) error {
authConfig := auth.AuthConfig{
Auths: []auth.Auth{authentity}}
dockerclient, err := runtime.NewDockerClient(runtime.WithAuth(authConfig))
if err != nil {
return err
}
for _, img := range imageNames {
_, err := dockerclient.Pull(img)
if err != nil {
log.Error(err)
continue
}
}
return nil
}
46 changes: 45 additions & 1 deletion veinmind-runner/pkg/authz/authz_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
defaultPluginPath = "plugin.log"
defaultAuthLogPath = "auth.log"
defaultSockListenAddr = "/run/docker/plugins/veinmind-broker.sock"
defaultPort = "8080"
)

type Policy struct {
Expand All @@ -23,6 +24,11 @@ type Policy struct {
Alert bool `toml:"alert"`
}

type HarborPolicy struct {
Policy
SendMail bool `toml:"send_mail"`
}

type Log struct {
AuthZLogPath string `toml:"auth_log_path"`
PluginLogPath string `toml:"plugin_log_path"`
Expand All @@ -31,13 +37,33 @@ type Log struct {
type Listener struct {
ListenAddr string `toml:"listener_addr"`
}

type Port struct {
Port string `toml:"port"`
}
type Password struct {
Password string `toml:"webhook_password"`
}
type MailConf struct {
Host string `toml:"host"`
Port int `toml:"port"`
Name string `toml:"username"`
Password string `toml:"password"`
SendTo []string `toml:"send_to"`
}
type DockerPluginConfig struct {
Log Log `toml:"log"`
Listener Listener `toml:"listener"`
DockerAuth auth.Auth `toml:"docker_auth"`
Policies []Policy `toml:"policies"`
}
type HarborWebhookConfig struct {
Log Log `toml:"log"`
Port Port `toml:"port"`
DockerAuth auth.Auth `toml:"docker_auth"`
Policies []HarborPolicy `toml:"policies"`
Password Password `toml:"password"`
MailConf MailConf `toml:"mail_conf"`
}

func NewDockerPluginConfig(paths ...string) (*DockerPluginConfig, error) {
if len(paths) < 1 {
Expand All @@ -57,3 +83,21 @@ func NewDockerPluginConfig(paths ...string) (*DockerPluginConfig, error) {

return result, nil
}
func NewHarborWebhookConfig(paths ...string) (*HarborWebhookConfig, error) {
if len(paths) < 1 {
return nil, errors.New("config path can't be empty")
}

path := defaultConfigPath
if paths[0] != "" {
path = paths[0]
}

result := &HarborWebhookConfig{}
_, err := toml.DecodeFile(path, result)
if err != nil {
return nil, err
}

return result, nil
}
54 changes: 44 additions & 10 deletions veinmind-runner/pkg/authz/authz_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"io"

gomail "gopkg.in/mail.v2"

"github.com/chaitin/libveinmind/go/plugin/log"
"github.com/chaitin/veinmind-common-go/service/report"
"github.com/chaitin/veinmind-tools/veinmind-runner/pkg/reporter"
Expand All @@ -25,30 +27,62 @@ func toLevelStr(level report.Level) string {
}

func handleReportEvents(eventListCh <-chan []reporter.ReportEvent, policy Policy,
pluginLog io.Writer) {
pluginLog io.Writer) (filter bool, results []reporter.ReportEvent) {
riskLevelFilter := make(map[string]struct{})
for _, level := range policy.RiskLevelFilter {
riskLevelFilter[level] = struct{}{}
}
select {
case events := <-eventListCh:
filter := true
for _, event := range events {
if _, ok := riskLevelFilter[toLevelStr(event.Level)]; !ok {
continue
}

filter = false
filter = true
results = append(results, event)
}
if err := reporter.WriteEvents2Log(events, pluginLog); err != nil {
log.Warn(err)
}
}
return filter, results
}
func handleDockerPluginReportEvents(eventListCh <-chan []reporter.ReportEvent, bpolicy Policy,
pluginLog io.Writer) {
filter, _ := handleReportEvents(eventListCh, bpolicy, pluginLog)
if filter {
if bpolicy.Alert {
log.Warn(fmt.Sprintf("Action %s has risks!", bpolicy.Action))
}
}
}

if !filter {
if policy.Alert {
log.Warn(fmt.Sprintf("Action %s has risks!", policy.Action))
func handleHarborWebhookReportEvents(eventListCh <-chan []reporter.ReportEvent, hpolicy HarborPolicy,
pluginLog io.Writer, mailconf MailConf) {
filter, events := handleReportEvents(eventListCh, hpolicy.Policy, pluginLog)
if filter {
if hpolicy.Alert {
log.Warn(fmt.Sprintf("Action %s has risks!", hpolicy.Action))
}
if hpolicy.SendMail {
err := sendReport2Mail(events, mailconf)
if err != nil {
log.Error(err)
}
}
}

if err := reporter.WriteEvents2Log(events, pluginLog); err != nil {
log.Warn(err)
}
}

func sendReport2Mail(events []reporter.ReportEvent, mailconf MailConf) error {
d := gomail.NewDialer(mailconf.Host, mailconf.Port, mailconf.Name, mailconf.Password)
m := gomail.NewMessage()
m.SetHeader("From", mailconf.Name)
m.SetHeader("To", mailconf.SendTo...)
m.SetHeader("Subject", "Harbor webhook Report")
m.SetBody("text/plain", fmt.Sprintf("%#v", events))
if err := d.DialAndSend(m); err != nil {
return err
}
return nil
}
Loading