Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Heartbeat] Setuid to regular user / lower capabilities when possible #27878

Merged
merged 51 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
88d2d1d
Checkpoint
andrewvc Sep 11, 2021
66d2e6b
Checkpoint
andrewvc Sep 11, 2021
f050f79
Checkpoint
andrewvc Sep 11, 2021
dbe92db
Add comment
andrewvc Sep 11, 2021
7413b0e
Fix unncessary changes
andrewvc Sep 11, 2021
0d791d9
Fix unncessary changes
andrewvc Sep 11, 2021
992a3c6
Cleanup
andrewvc Sep 11, 2021
f938856
Add license override
andrewvc Sep 11, 2021
58ef9a3
Be more particular
andrewvc Sep 11, 2021
b295517
Tweaks
andrewvc Sep 11, 2021
206b346
Checkpoint
andrewvc Sep 12, 2021
576ca31
Checkpoint
andrewvc Sep 13, 2021
7e26638
Checkpoint
andrewvc Sep 13, 2021
61ae19c
SECCOMP Checkpoint
andrewvc Sep 13, 2021
fa24f7e
More fixes
andrewvc Sep 13, 2021
61542a0
Cleanup and fixes
andrewvc Sep 13, 2021
eaadc02
More fixes
andrewvc Sep 13, 2021
2835b98
CHANGELOG
andrewvc Sep 13, 2021
faa0989
More tweaks
andrewvc Sep 13, 2021
84d7eac
Rename seccomp->security
andrewvc Sep 13, 2021
ddbbf6e
Fix overrides
andrewvc Sep 13, 2021
1623137
Fix seccomp.go
andrewvc Sep 14, 2021
e1799f6
Cleanup
andrewvc Sep 14, 2021
94f95e4
Merge remote-tracking branch 'origin/master' into root-caps
andrewvc Sep 14, 2021
bf90094
Fix lint
andrewvc Sep 14, 2021
d055eb7
Fix lint
andrewvc Sep 14, 2021
7ba5301
separate setcaps
andrewvc Sep 14, 2021
f757217
Apply security to regular heartbeat too
andrewvc Sep 14, 2021
9b7c6e6
Only lookup groups etc. on linux
andrewvc Sep 14, 2021
793214e
Use simpler logic
andrewvc Sep 14, 2021
0aa410c
Fix lint
andrewvc Sep 14, 2021
c9532f3
Make portable to win/darwin
andrewvc Sep 20, 2021
cee1ad6
Fix setcap notation
andrewvc Sep 21, 2021
de41310
Make debugging build failure simpler
andrewvc Sep 21, 2021
3cafd9c
Merge branch 'master' into root-caps
mergify[bot] Sep 21, 2021
1ad68d3
Merge branch 'master' into root-caps
mergify[bot] Sep 22, 2021
7cddfa8
Merge branch 'master' into root-caps
mergify[bot] Sep 23, 2021
1a90113
Only target linux x86/amd64
andrewvc Sep 27, 2021
9dcd749
Merge branch 'root-caps' of github.com:andrewvc/beats into root-caps
andrewvc Sep 27, 2021
735aa76
Merge remote-tracking branch 'origin/master' into root-caps
andrewvc Sep 27, 2021
ea805d9
Fix setcap syntax
andrewvc Sep 27, 2021
0a292ee
Fix extra trailing slash
andrewvc Sep 27, 2021
bdc4c19
Fix setcap
andrewvc Sep 28, 2021
6a49b88
Follow link for setcap
andrewvc Sep 30, 2021
64a9d9e
fix
andrewvc Sep 30, 2021
c55cd77
Finalize
andrewvc Oct 1, 2021
7c2fc33
Merge remote-tracking branch 'origin/master' into root-caps
andrewvc Oct 1, 2021
d5da29c
Remove stdout
andrewvc Oct 1, 2021
39218ae
Incorporate PR feedback
andrewvc Oct 1, 2021
393bd27
Merge remote-tracking branch 'origin/master' into root-caps
andrewvc Oct 12, 2021
70fcce6
Update heartbeat security
andrewvc Oct 12, 2021
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
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

- Fixed excessive memory usage introduced in 7.5 due to over-allocating memory for HTTP checks. {pull}15639[15639]
- Fixed TCP TLS checks to properly validate hostnames, this broke in 7.x and only worked for IP SANs. {pull}17549[17549]
- Fix broken seccomp filtering and improve security via `setcap` and `setuid` when running as root on linux in containers. {pull}27878[27878]

*Journalbeat*

Expand Down
1 change: 1 addition & 0 deletions dev-tools/notice/overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
{"name": "github.com/munnerz/goautoneg", "licenceType": "BSD-3-Clause"}
{"name": "github.com/pelletier/go-buffruneio", "licenceType": "MIT"}
{"name": "github.com/urso/magetools", "licenceType": "Apache-2.0"}
{"name": "kernel.org/pub/linux/libs/security/libcap/cap", "licenseFile": "License", "licenseType": "BSD-3-Clause", "note": "Dual licensed as BSD-3-Clause / GPL-2.0. See https://git.kernel.org/pub/scm/libs/libcap/libcap.git/tree/License"}
2 changes: 1 addition & 1 deletion dev-tools/packaging/packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ shared:
dockerfile: 'Dockerfile.elastic-agent.tmpl'
docker_entrypoint: 'docker-entrypoint.elastic-agent.tmpl'
user: '{{ .BeatName }}'
linux_capabilities: ''
linux_capabilities: 'net_raw+eip'
files:
'elastic-agent.yml':
source: 'elastic-agent.docker.yml'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ FROM {{ .from }}
# Contains the elastic agent image variant, an empty string for the standard variant
# or "complete" for the bigger one.
ENV ELASTIC_AGENT_IMAGE_VARIANT={{.Variant}}
ENV BEAT_SETUID_AS={{ .user }}

{{- if contains .from "ubi-minimal" }}
RUN for iter in {1..10}; do microdnf update -y && microdnf install -y shadow-utils jq && microdnf clean all && exit_code=0 && break || exit_code=$? && echo "microdnf error: retry $iter in 10s" && sleep 10; done; (exit $exit_code)
Expand Down
1 change: 1 addition & 0 deletions dev-tools/packaging/templates/docker/Dockerfile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ USER {{ .user }}
{{- if (and (eq .BeatName "heartbeat") (not (contains .from "ubi-minimal"))) }}
# Setup synthetics env vars
ENV ELASTIC_SYNTHETICS_CAPABLE=true
ENV BEAT_SETUID_AS={{ .user }}
ENV SUITES_DIR={{ $beatHome }}/suites
ENV NODE_VERSION=14.17.5
ENV PATH="$NODE_PATH/node/bin:$PATH"
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ require (
k8s.io/api v0.19.4
k8s.io/apimachinery v0.19.4
k8s.io/client-go v0.19.4
kernel.org/pub/linux/libs/security/libcap/cap v1.2.57
)

replace (
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,10 @@ k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.57 h1:2nmqI+aw7EQZuelYktkQHBE4jESD2tOR+lOJEnv/Apo=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.57/go.mod h1:uI99C3r4SXvJeuqoEtx/eWt7UbmfqqZ80H8q+9t/A7I=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.57 h1:NOFATXSf5z/cMR3HIwQ3Xrd3nwnWl5xThmNr5U/F0pI=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.57/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
Expand Down
4 changes: 4 additions & 0 deletions heartbeat/beater/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package beater
import (
"errors"
"fmt"
"syscall"
"time"

"github.com/elastic/beats/v7/heartbeat/config"
Expand All @@ -33,6 +34,7 @@ import (
"github.com/elastic/beats/v7/libbeat/common/reload"
"github.com/elastic/beats/v7/libbeat/logp"
"github.com/elastic/beats/v7/libbeat/management"
"kernel.org/pub/linux/libs/security/libcap/cap"

_ "github.com/elastic/beats/v7/libbeat/processors/script"
)
Expand Down Expand Up @@ -80,6 +82,8 @@ func New(b *beat.Beat, rawConfig *common.Config) (beat.Beater, error) {
// Run executes the beat.
func (bt *Heartbeat) Run(b *beat.Beat) error {
logp.Info("heartbeat is running! Hit CTRL-C to stop it.")
groups, _ := syscall.Getgroups()
logp.Info("Effective user/group ids: %d/%d, with groups: %v, and with capabilities: %s", syscall.Geteuid(), syscall.Getegid(), groups, cap.GetProc())

stopStaticMonitors, err := bt.RunStaticMonitors(b)
if err != nil {
Expand Down
12 changes: 5 additions & 7 deletions x-pack/heartbeat/monitors/browser/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ package browser
import (
"fmt"
"os"
"os/user"
"sync"
"syscall"

"github.com/elastic/beats/v7/heartbeat/monitors/plugin"
"github.com/elastic/beats/v7/libbeat/common"
Expand All @@ -35,12 +35,10 @@ func create(name string, cfg *common.Config) (p plugin.Plugin, err error) {
logp.Info("Synthetic browser monitor detected! Please note synthetic monitors are a beta feature!")
})

curUser, err := user.Current()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need to be here even now? If we havent set BEAT_SETUID_AS, do we run as heartbeat user?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, in that case we're running as root, and we bail with the error message. If that env var isn't set we don't know who to run as and we can't figure it out any other way. Keep in mind heartbeat is only the correct user in the heartbeat docker image. In the elastic-agent container the correct user is elastic-agent

if err != nil {
return plugin.Plugin{}, fmt.Errorf("could not determine current user for script monitor %w: ", err)
}
if curUser.Uid == "0" {
return plugin.Plugin{}, fmt.Errorf("script monitors cannot be run as root! Current UID is %s", curUser.Uid)
// We do not use user.Current() which does not reflect setuid changes!
if syscall.Geteuid() == 0 {
euid := syscall.Geteuid()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this basically a dead code as its 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch lol

return plugin.Plugin{}, fmt.Errorf("script monitors cannot be run as root! Current EUID is %d", euid)
}

s, err := NewSuite(cfg)
Expand Down
3 changes: 2 additions & 1 deletion x-pack/heartbeat/monitors/browser/source/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os/exec"
"path"
"path/filepath"
"syscall"

"github.com/elastic/beats/v7/libbeat/logp"

Expand Down Expand Up @@ -142,6 +143,6 @@ func runSimpleCommand(cmd *exec.Cmd, dir string) error {
cmd.Dir = dir
logp.Info("Running %s in %s", cmd, dir)
output, err := cmd.CombinedOutput()
logp.Info("Ran %s got %s", cmd, string(output))
logp.Info("Ran %s (%d) got '%s': (%s) as (%d/%d)", cmd, cmd.ProcessState.ExitCode(), string(output), err, syscall.Getuid(), syscall.Geteuid())
return err
}
9 changes: 6 additions & 3 deletions x-pack/heartbeat/monitors/browser/source/zipurl.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/elastic/beats/v7/libbeat/common/transport/httpcommon"
"github.com/elastic/beats/v7/libbeat/logp"
)

type ZipURLSource struct {
Expand Down Expand Up @@ -112,8 +113,10 @@ func unzip(tf *os.File, targetDir string, folder string) error {
for _, f := range rdr.File {
err = unzipFile(targetDir, folder, f)
if err != nil {
// TODO: err handlers
os.RemoveAll(targetDir)
rmErr := os.RemoveAll(targetDir)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came up during testing syscall stuff

if rmErr != nil {
return fmt.Errorf("could not remove directory after encountering error unzipping file: %w, (original unzip error: %s)", rmErr, err)
}
return err
}
}
Expand Down Expand Up @@ -186,6 +189,7 @@ func retryingZipRequest(method string, z *ZipURLSource) (resp *http.Response, er
if err == nil {
resp.Body.Close()
}
logp.Info("attempt to download zip at %s failed: %s, will retry in 1s", z.URL, err)
time.Sleep(time.Second)
}
if resp != nil && resp.StatusCode > 300 {
Expand All @@ -195,7 +199,6 @@ func retryingZipRequest(method string, z *ZipURLSource) (resp *http.Response, er
}

func zipRequest(method string, z *ZipURLSource) (*http.Response, error) {

req, err := http.NewRequest(method, z.URL, nil)
if err != nil {
return nil, fmt.Errorf("could not issue request to: %s %w", z.URL, err)
Expand Down
83 changes: 0 additions & 83 deletions x-pack/heartbeat/seccomp_linux.go

This file was deleted.

Loading