diff --git a/cmd/deploy.go b/cmd/deploy.go index fded27c1a..4936b6d87 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -155,6 +155,12 @@ func deployFn(_ *cobra.Command, _ []string) error { log.Info("Creating lab directory: ", c.TopoPaths.TopologyLabDir()) utils.CreateDirectory(c.TopoPaths.TopologyLabDir(), 0755) + // adjust ACL for Labdir such that SUDO_UID Users will + // also have access to lab directory files + err = utils.AdjustFileACLs(c.TopoPaths.TopologyLabDir()) + if err != nil { + log.Infof("unable to adjust Labdir file ACLs: %v", err) + } // create an empty ansible inventory file that will get populated later // we create it here first, so that bind mounts of ansible-inventory.yml file could work diff --git a/go.mod b/go.mod index 4559a3b39..7b4e9136a 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/scrapli/scrapligo v1.2.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 + github.com/steiler/acls v0.1.0 github.com/stretchr/testify v1.8.4 github.com/tklauser/numcpus v0.6.1 github.com/vishvananda/netlink v1.2.1-beta.2 diff --git a/go.sum b/go.sum index b2227e95b..ab1797247 100644 --- a/go.sum +++ b/go.sum @@ -2678,6 +2678,12 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 h1:lIOOHPEbXzO3vnmx2gok1Tfs31Q8GQqKLc8vVqyQq/I= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/steiler/acls v0.0.0-20231106135104-9c34ae82c793 h1:lY8SggLL0JyttzcNEIRzbywKiKcIlVlF7ZPwTthG9eA= +github.com/steiler/acls v0.0.0-20231106135104-9c34ae82c793/go.mod h1:kS9/GuHDS4t2YmY2ijbaK3m1iU4+BgRZS7GoDTC9BfY= +github.com/steiler/acls v0.0.0-20231106152733-bb3d5d7b05c8 h1:RqP82h2DREJxj7AJbT0k7z2Jye6lweij5s14PUHic1o= +github.com/steiler/acls v0.0.0-20231106152733-bb3d5d7b05c8/go.mod h1:kS9/GuHDS4t2YmY2ijbaK3m1iU4+BgRZS7GoDTC9BfY= +github.com/steiler/acls v0.1.0 h1:fKVnEJ7ebghq2Ed5N1cU9fZrCCRj4xVRPrP7OswaRX8= +github.com/steiler/acls v0.1.0/go.mod h1:kS9/GuHDS4t2YmY2ijbaK3m1iU4+BgRZS7GoDTC9BfY= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= diff --git a/utils/file.go b/utils/file.go index 82e466d4d..9f29c6291 100644 --- a/utils/file.go +++ b/utils/file.go @@ -18,8 +18,11 @@ import ( "os/exec" "os/user" "path/filepath" + "strconv" "strings" + "github.com/steiler/acls" + log "github.com/sirupsen/logrus" ) @@ -333,6 +336,8 @@ func FileLines(path, commentStr string) ([]string, error) { return lines, nil } +// NewHTTPClient creates a new HTTP client with +// insecure skip verify set to true and min TLS version set to 1.2. func NewHTTPClient() *http.Client { // set InsecureSkipVerify to true to allow fetching // files form servers with self-signed certificates @@ -345,3 +350,60 @@ func NewHTTPClient() *http.Client { return &http.Client{Transport: tr} } + +// AdjustFileACLs takes the given fs path, tries to load +// the access file acl of that path and adds ACL rules +// rwx for the SUDO_UID and r-x for the SUDO_GID group. +func AdjustFileACLs(fsPath string) error { + /// here we trust sudo to set up env variables + // a missing SUDO_UID env var indicates the root user + // runs clab without sudo + uid, isSet := os.LookupEnv("SUDO_UID") + if !isSet { + // nothing to do, already running as root + return nil + } + + gid, isSet := os.LookupEnv("SUDO_GID") + if !isSet { + return fmt.Errorf("unable to retrieve GID. will only adjust UID for %q", fsPath) + } + + iUID, err := strconv.Atoi(uid) + if err != nil { + return fmt.Errorf("unable to convert SUDO_UID %q to int", uid) + } + + iGID, err := strconv.Atoi(gid) + if err != nil { + return fmt.Errorf("unable to convert SUDO_GID %q to int", gid) + } + + // create a new ACL instance + a := &acls.ACL{} + // load the existing ACL entries of the PosixACLAccess type + err = a.Load(fsPath, acls.PosixACLAccess) + if err != nil { + return err + } + + // add an entry for the group + err = a.AddEntry(acls.NewEntry(acls.TAG_ACL_GROUP, uint32(iGID), 5)) + if err != nil { + return err + } + + // add an entry for the User + err = a.AddEntry(acls.NewEntry(acls.TAG_ACL_USER, uint32(iUID), 7)) + if err != nil { + return err + } + + // apply the ACL and return the error result + err = a.Apply(fsPath, acls.PosixACLAccess) + if err != nil { + return err + } + + return a.Apply(fsPath, acls.PosixACLDefault) +}