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

Set config file mode to 0600 in packages #3382

Merged
merged 3 commits into from
Jan 17, 2017
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ https://github.com/elastic/beats/compare/v5.1.1...master[Check the HEAD diff]
- The limit for the number of fields is increased via the mapping template. {pull}3275[3275]
- Updated to Go 1.7.4. {pull}3277[3277]
- Added a NOTICE file containing the notices and licenses of the dependencies. {pull}3334[3334].
- RPM/deb packages will now install the config file with 0600 permissions. {pull}3382[3382]

*Metricbeat*

Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ package: update beats-dashboards
mkdir -p build/upload/
$(foreach var,$(BEATS),cp -r $(var)/build/upload/ build/upload/$(var) || exit 1;)
cp -r build/dashboards-upload build/upload/dashboards
# Run tests on the generated packages.
go test ./dev-tools/package_test.go -files "${shell pwd}/build/upload/*/*"

# Upload nightly builds to S3
.PHONY: upload-nightlies-s3
Expand Down
18 changes: 18 additions & 0 deletions dev-tools/glide.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package: github.com/elastic/beats/dev-tools
import: []
testImports:
Copy link
Member

Choose a reason for hiding this comment

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

wasn't aware of this glide feature.

- name: github.com/blakesmith/ar
version: 8bd4349a67f2533b078dbc524689d15dba0f4659
- name: github.com/cavaliercoder/go-rpm
version: 9664735b838ea0a81e4aace3197ebe0d4040f952
- name: golang.org/x/crypto
version: 2f8be38b9a7533b8763d48273737ff6e90428a96
subpackages:
- cast5
- openpgp
- openpgp/armor
- openpgp/elgamal
- openpgp/errors
- openpgp/packet
- openpgp/s2k

289 changes: 289 additions & 0 deletions dev-tools/package_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
package dev_tools

// This file contains tests that can be run on the generated packages.
// To run these tests use `go test package_test.go`.

import (
"archive/tar"
"archive/zip"
"bytes"
"compress/gzip"
"flag"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"testing"

"github.com/blakesmith/ar"
Copy link
Member

Choose a reason for hiding this comment

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

Could we add a vendor directory to the dev-tools directory? I would prefer if we don't mix vendor packages for tools with actual libbeat / beats dependencies. This makes it easier to track where a dependency belongs to.

Long term I'm thinking also to move dependencies which only belong to one beat into the beat if possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I can move these to dev-tools. I was thinking about that when I added them because glide was giving lots of errors and also because I wanted it to be clear that these deps were not used in any Beat that we release.

Copy link
Member Author

Choose a reason for hiding this comment

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

I update the PR to move the dependencies to ./dev-tools/vendor.

"github.com/cavaliercoder/go-rpm"
)

const (
expectedConfigMode = os.FileMode(0600)
expectedConfigUID = 0
expectedConfigGID = 0
)

var (
configFilePattern = regexp.MustCompile(`.*beat\.yml`)
)

var (
files = flag.String("files", "../build/upload/*/*", "filepath glob containing package files")
)

func TestRPM(t *testing.T) {
rpms := getFiles(t, regexp.MustCompile(`\.rpm$`))
for _, rpm := range rpms {
checkRPM(t, rpm)
}
}

func TestDeb(t *testing.T) {
debs := getFiles(t, regexp.MustCompile(`\.deb$`))
buf := new(bytes.Buffer)
for _, deb := range debs {
checkDeb(t, deb, buf)
}
}

func TestTar(t *testing.T) {
tars := getFiles(t, regexp.MustCompile(`\.tar\.gz$`))
for _, tar := range tars {
checkTar(t, tar)
}
}

func TestZip(t *testing.T) {
zips := getFiles(t, regexp.MustCompile(`^\w+beat-\S+.zip$`))
for _, zip := range zips {
checkZip(t, zip)
}
}

// Sub-tests

func checkRPM(t *testing.T, file string) {
p, err := readRPM(file)
if err != nil {
t.Error(err)
return
}

checkConfigPermissions(t, p)
}

func checkDeb(t *testing.T, file string, buf *bytes.Buffer) {
p, err := readDeb(file, buf)
if err != nil {
t.Error(err)
return
}

checkConfigPermissions(t, p)
checkConfigOwner(t, p)
}

func checkTar(t *testing.T, file string) {
p, err := readTar(file)
if err != nil {
t.Error(err)
return
}

checkConfigPermissions(t, p)
checkConfigOwner(t, p)
}

func checkZip(t *testing.T, file string) {
p, err := readZip(file)
if err != nil {
t.Error(err)
return
}

checkConfigPermissions(t, p)
}

// Verify that the main configuration file is installed with a 0600 file mode.
func checkConfigPermissions(t *testing.T, p *packageFile) {
t.Run(p.Name+" config file permissions", func(t *testing.T) {
for _, entry := range p.Contents {
if configFilePattern.MatchString(entry.File) {
mode := entry.Mode.Perm()
if expectedConfigMode != mode {
t.Errorf("file %v has wrong permissions: expected=%v actual=%v",
entry.Mode, expectedConfigMode, mode)
}
return
}
}
t.Errorf("no config file found matching %v", configFilePattern)
})
}

func checkConfigOwner(t *testing.T, p *packageFile) {
t.Run(p.Name+" config file owner", func(t *testing.T) {
for _, entry := range p.Contents {
if configFilePattern.MatchString(entry.File) {
if expectedConfigUID != entry.UID {
t.Errorf("file %v should be owned by user %v, owner=%v", entry.File, expectedConfigGID, entry.UID)
}
if expectedConfigGID != entry.GID {
t.Errorf("file %v should be owned by group %v, group=%v", entry.File, expectedConfigGID, entry.GID)
}
return
}
}
t.Errorf("no config file found matching %v", configFilePattern)
})
}

// Helpers

type packageFile struct {
Name string
Contents map[string]packageEntry
}

type packageEntry struct {
File string
UID int
GID int
Mode os.FileMode
}

func getFiles(t *testing.T, pattern *regexp.Regexp) []string {
matches, err := filepath.Glob(*files)
if err != nil {
t.Fatal(err)
}

files := matches[:0]
for _, f := range matches {
if pattern.MatchString(filepath.Base(f)) {
files = append(files, f)
}
}

return files
}

func readRPM(rpmFile string) (*packageFile, error) {
p, err := rpm.OpenPackageFile(rpmFile)
if err != nil {
return nil, err
}

contents := p.Files()
pf := &packageFile{Name: filepath.Base(rpmFile), Contents: map[string]packageEntry{}}

for _, file := range contents {
pf.Contents[file.Name()] = packageEntry{
File: file.Name(),
Mode: file.Mode(),
}
}

return pf, nil
}

// readDeb reads the data.tar.gz file from the .deb.
func readDeb(debFile string, dataBuffer *bytes.Buffer) (*packageFile, error) {
file, err := os.Open(debFile)
if err != nil {
return nil, err
}
defer file.Close()

arReader := ar.NewReader(file)
for {
header, err := arReader.Next()
if err != nil {
if err == io.EOF {
break
}
return nil, err
}

if strings.HasPrefix(header.Name, "data.tar.gz") {
dataBuffer.Reset()
_, err := io.Copy(dataBuffer, arReader)
if err != nil {
return nil, err
}

gz, err := gzip.NewReader(dataBuffer)
if err != nil {
return nil, err
}
defer gz.Close()

return readTarContents(filepath.Base(debFile), gz)
}
}

return nil, io.EOF
}

func readTar(tarFile string) (*packageFile, error) {
file, err := os.Open(tarFile)
if err != nil {
return nil, err
}
defer file.Close()

var fileReader io.ReadCloser = file
if strings.HasSuffix(tarFile, ".gz") {
if fileReader, err = gzip.NewReader(file); err != nil {
return nil, err
}
defer fileReader.Close()
}

return readTarContents(filepath.Base(tarFile), fileReader)
}

func readTarContents(tarName string, data io.Reader) (*packageFile, error) {
tarReader := tar.NewReader(data)

p := &packageFile{Name: tarName, Contents: map[string]packageEntry{}}
for {
header, err := tarReader.Next()
if err != nil {
if err == io.EOF {
break
}
return nil, err
}

p.Contents[header.Name] = packageEntry{
File: header.Name,
UID: header.Uid,
GID: header.Gid,
Mode: os.FileMode(header.Mode),
}
}

return p, nil
}

func readZip(zipFile string) (*packageFile, error) {
r, err := zip.OpenReader(zipFile)
if err != nil {
return nil, err
}
defer r.Close()

p := &packageFile{Name: filepath.Base(zipFile), Contents: map[string]packageEntry{}}
for _, f := range r.File {
p.Contents[f.Name] = packageEntry{
File: f.Name,
Mode: f.Mode(),
}
}

return p, nil
}
3 changes: 3 additions & 0 deletions dev-tools/packer/xgo-scripts/before_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ cp $BEAT_NAME.template-es2x.json $PREFIX/$BEAT_NAME.template-es2x.json

# linux
cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-linux.yml
chmod 0600 $PREFIX/$BEAT_NAME-linux.yml
cp $BEAT_NAME.full.yml $PREFIX/$BEAT_NAME-linux.full.yml

# darwin
cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-darwin.yml
chmod 0600 $PREFIX/$BEAT_NAME-darwin.yml
cp $BEAT_NAME.full.yml $PREFIX/$BEAT_NAME-darwin.full.yml

# win
cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-win.yml
chmod 0600 $PREFIX/$BEAT_NAME-win.yml
cp $BEAT_NAME.full.yml $PREFIX/$BEAT_NAME-win.full.yml

# Contains beat specific adjustments. As it is platform specific knowledge, it should be in packer not the beats itself
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading