Skip to content

Commit

Permalink
Merge branch 'main' of github.com:elastic/elastic-agent into feat/rel…
Browse files Browse the repository at this point in the history
…ax-server
  • Loading branch information
michalpristas committed Oct 23, 2023
2 parents 9b65627 + 92acf08 commit 0366ce4
Show file tree
Hide file tree
Showing 51 changed files with 1,468 additions and 543 deletions.
4 changes: 2 additions & 2 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1799,11 +1799,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-transpo

--------------------------------------------------------------------------------
Dependency : github.com/elastic/go-elasticsearch/v8
Version: v8.10.0
Version: v8.10.1
Licence type (autodetected): Apache-2.0
--------------------------------------------------------------------------------

Contents of probable licence file $GOMODCACHE/github.com/elastic/go-elasticsearch/[email protected].0/LICENSE:
Contents of probable licence file $GOMODCACHE/github.com/elastic/go-elasticsearch/[email protected].1/LICENSE:

Apache License
Version 2.0, January 2004
Expand Down
6 changes: 3 additions & 3 deletions dev-tools/cmd/buildpgp/build_pgp.go

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

176 changes: 176 additions & 0 deletions docs/pgp-sign-verify-artifact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Signing Elastic Agent artifacts

This doc covers generating a key, exporting the public key, signing a file and verifying it using GPG as well as pure Go.

Full GPG docs: https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Key-Management.html


## Go

```go
package main

import (
"bytes"
"fmt"
"os"
"path/filepath"

"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
)

func main() {
dir, err := os.MkdirTemp(os.TempDir(), "pgp-")
NoError(err, "could not create directory to save the files to")

key := filepath.Join(dir, "key")
keyPub := filepath.Join(dir, "key.pub")
asc := filepath.Join(dir, "plaindata.asc")

fmt.Printf("Writing files to %q\n", dir)

data := []byte("some data")
plaindata := filepath.Join(dir, "plaindata")
err = os.WriteFile(plaindata, data, 0o600)
NoError(err, "could not write plain data file")

fmt.Printf("wrote %q\n", plaindata)

// Create files
fKeyPub, err := os.OpenFile(
keyPub,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
NoError(err, "could not create %q file", keyPub)
defer func() {
if err := fKeyPub.Close(); err != nil {
fmt.Printf("failed closing %q\n", fKeyPub.Name())
}
fmt.Printf("wrote %q\n", fKeyPub.Name())
}()

fKey, err := os.OpenFile(
key,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
NoError(err, "could not create %q file", key)
defer func() {
if err := fKey.Close(); err != nil {
fmt.Printf("failed closing %q\n", fKey.Name())
}
fmt.Printf("wrote %q\n", fKey.Name())
}()

fasc, err := os.OpenFile(
asc,
os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
NoError(err, "could not create %q file", asc)
defer func() {
if err := fasc.Close(); err != nil {
fmt.Printf("failed closing %q\n", fasc.Name())
}
fmt.Printf("wrote %q\n", fasc.Name())
}()

// Generate PGP key
entity, err := openpgp.NewEntity("someKeyName", "", "", nil)

// Create an ASCII armored encoder to serialize the private key
wPubKey, err := armor.Encode(fKeyPub, openpgp.PublicKeyType, nil)
NoError(err, "could not create PGP ASCII Armor encoder for public key")
defer func() {
err := wPubKey.Close()
if err != nil {
fmt.Println("failed closing private key writer")
}
}()

// Writes the public key to the io.Writer passed to armor.Encode.
// Use entity.SerializePrivate if you need the private key.
err = entity.Serialize(wPubKey)
NoError(err, "could not serialize the public key")

// Create an ASCII armored encoder to serialize the private key
wPrivKey, err := armor.Encode(fKey, openpgp.PrivateKeyType, nil)
NoError(err, "could not create PGP ASCII Armor encoder for private key")
defer func() {
err := wPrivKey.Close()
if err != nil {
fmt.Println("failed closing private key writer")
}
}()

// Writes the private key to the io.Writer passed to armor.Encode.
// Use entity.SerializePrivate if you need the private key.
err = entity.SerializePrivate(wPrivKey, nil)
NoError(err, "could not serialize the private key")

// Sign data and write the detached signature to fasc
err = openpgp.ArmoredDetachSign(fasc, entity, bytes.NewReader(data), nil)
NoError(err, "failed signing date")
}

func NoError(err error, msg string, args ...any) {
if err != nil {
panic(fmt.Sprintf(msg+": %v", append(args, err)))
}
}
```

## GPG
### Generate a key

```shell
gpg --no-default-keyring --keyring ./some-file-to-be-the-key-ring --quick-generate-key atest rsa2048 default none
```
Where:
- `--no-default-keyring`: do not use your keyring
- `--keyring ./some-file-to-be-the-key-ring`: keyring to use, as the file do not exist, it'll create it
- `--quick-generate-key`: quick generate the key
- `atest`: user-id, a.k.a the key identifier
- `rsa2048`: algorithm to use
- `default`: "usage" for the key. Just use default
- `none`: key expiration


### Export the public key
```shell
gpg --no-default-keyring --keyring ./some-file-to-be-the-key-ring --armor --output public-key.pgp --export atest
```
Where:
- `--no-default-keyring`: do not use your keyring
- `--keyring ./some-file-to-be-the-key-ring`: the keyring to use, created in the previous step
- `--armor`: create ASCII armoured output. Otherwise, it's a binary format
- `--output public-key.pgp`: the output file
- `--export`: export the public key
- `atest`: the key identifier

### Sing the file
```shell
gpg --no-default-keyring --keyring ./some-file-to-be-the-key-ring -a -o elastic-agent-8.0.0-darwin-x86_64.tar.gz.asc --detach-sign elastic-agent-8.0.0-darwin-x86_64.tar.gz
```

Where:
- `-a -o`: --armored, --output
- `elastic-agent-8.0.0-darwin-x86_64.tar.gz.asc`: the output file
- `--detach-sign`: generate a separated file for signature
- `elastic-agent-8.0.0-darwin-x86_64.tar.gz`: the file to sign



### Verify the file

#### Import the public key
```shell
gpg --no-default-keyring --keyring ./new-keyring --import public-key.pgp
```
Where:
- `--import`: import a key
- `public-key.pgp`: the key to import

#### Verify the signature using the imported key
```shell
gpg --no-default-keyring --keyring ./new-keyring --verify elastic-agent-8.0.0-darwin-x86_64.tar.gz.asc
```
Where:
- `--verify`: verify a signature
- `elastic-agent-8.0.0-darwin-x86_64.tar.gz.asc`: the detached signature file. It'll assume the file to be verified is `elastic-agent-8.0.0-darwin-x86_64.tar.gz`
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/elastic/elastic-agent-libs v0.6.0
github.com/elastic/elastic-agent-system-metrics v0.7.0
github.com/elastic/elastic-transport-go/v8 v8.3.0
github.com/elastic/go-elasticsearch/v8 v8.10.0
github.com/elastic/go-elasticsearch/v8 v8.10.1
github.com/elastic/go-licenser v0.4.1
github.com/elastic/go-sysinfo v1.11.1
github.com/elastic/go-ucfg v0.8.6
Expand Down
5 changes: 2 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -787,13 +787,12 @@ github.com/elastic/elastic-agent-system-metrics v0.7.0 h1:qDLY30UDforSd/TfHfqUDi
github.com/elastic/elastic-agent-system-metrics v0.7.0/go.mod h1:9C1UEfj0P687HAzZepHszN6zXA+2tN2Lx3Osvq1zby8=
github.com/elastic/elastic-integration-corpus-generator-tool v0.5.0/go.mod h1:uf9N86y+UACGybdEhZLpwZ93XHWVhsYZAA4c2T2v6YM=
github.com/elastic/elastic-package v0.77.0/go.mod h1:Xeqx0OOVnKBfFoSHsHmKI74RxgRGiDhU6yXEu8BkJJM=
github.com/elastic/elastic-transport-go/v8 v8.0.0-20230329154755-1a3c63de0db6/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI=
github.com/elastic/elastic-transport-go/v8 v8.3.0 h1:DJGxovyQLXGr62e9nDMPSxRyWION0Bh6d9eCFBriiHo=
github.com/elastic/elastic-transport-go/v8 v8.3.0/go.mod h1:87Tcz8IVNe6rVSLdBux1o/PEItLtyabHU3naC7IoqKI=
github.com/elastic/go-elasticsearch/v7 v7.17.7/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
github.com/elastic/go-elasticsearch/v8 v8.0.0-20210317102009-a9d74cec0186/go.mod h1:xe9a/L2aeOgFKKgrO3ibQTnMdpAeL0GC+5/HpGScSa4=
github.com/elastic/go-elasticsearch/v8 v8.10.0 h1:ALg3DMxSrx07YmeMNcfPf7cFh1Ep2+Qa19EOXTbwr2k=
github.com/elastic/go-elasticsearch/v8 v8.10.0/go.mod h1:NGmpvohKiRHXI0Sw4fuUGn6hYOmAXlyCphKpzVBiqDE=
github.com/elastic/go-elasticsearch/v8 v8.10.1 h1:JJ3i2DimYTsJcUoEGbg6tNB0eehTNdid9c5kTR1TGuI=
github.com/elastic/go-elasticsearch/v8 v8.10.1/go.mod h1:GU1BJHO7WeamP7UhuElYwzzHtvf9SDmeVpSSy9+o6Qg=
github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ=
github.com/elastic/go-licenser v0.4.0/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU=
github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/elastic/elastic-agent/internal/pkg/agent/application/coordinator"
"github.com/elastic/elastic-agent/internal/pkg/agent/application/info"
"github.com/elastic/elastic-agent/internal/pkg/agent/application/reexec"
"github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details"
"github.com/elastic/elastic-agent/internal/pkg/agent/configuration"
"github.com/elastic/elastic-agent/internal/pkg/config"
"github.com/elastic/elastic-agent/internal/pkg/fleetapi"
Expand All @@ -35,7 +36,7 @@ func (u *mockUpgradeManager) Reload(rawConfig *config.Config) error {
return nil
}

func (u *mockUpgradeManager) Upgrade(ctx context.Context, version string, sourceURI string, action *fleetapi.ActionUpgrade, skipVerifyOverride bool, skipDefaultPgp bool, pgpBytes ...string) (_ reexec.ShutdownCallbackFn, err error) {
func (u *mockUpgradeManager) Upgrade(ctx context.Context, version string, sourceURI string, action *fleetapi.ActionUpgrade, details *details.Details, skipVerifyOverride bool, skipDefaultPgp bool, pgpBytes ...string) (_ reexec.ShutdownCallbackFn, err error) {
select {
case <-time.After(2 * time.Second):
u.msgChan <- "completed " + version
Expand Down
46 changes: 38 additions & 8 deletions internal/pkg/agent/application/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import (

"github.com/elastic/elastic-agent-client/v7/pkg/client"
"github.com/elastic/elastic-agent-libs/logp"

"github.com/elastic/elastic-agent/internal/pkg/agent/application/info"
"github.com/elastic/elastic-agent/internal/pkg/agent/application/reexec"
"github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details"
"github.com/elastic/elastic-agent/internal/pkg/agent/configuration"
"github.com/elastic/elastic-agent/internal/pkg/agent/transpiler"
"github.com/elastic/elastic-agent/internal/pkg/capabilities"
Expand Down Expand Up @@ -59,7 +61,7 @@ type UpgradeManager interface {
Reload(rawConfig *config.Config) error

// Upgrade upgrades running agent.
Upgrade(ctx context.Context, version string, sourceURI string, action *fleetapi.ActionUpgrade, skipVerifyOverride bool, skipDefaultPgp bool, pgpBytes ...string) (_ reexec.ShutdownCallbackFn, err error)
Upgrade(ctx context.Context, version string, sourceURI string, action *fleetapi.ActionUpgrade, details *details.Details, skipVerifyOverride bool, skipDefaultPgp bool, pgpBytes ...string) (_ reexec.ShutdownCallbackFn, err error)

// Ack is used on startup to check if the agent has upgraded and needs to send an ack for the action
Ack(ctx context.Context, acker acker.Acker) error
Expand Down Expand Up @@ -108,7 +110,7 @@ type RuntimeManager interface {
// it performs diagnostics for all current units.
PerformDiagnostics(context.Context, ...runtime.ComponentUnitDiagnosticRequest) []runtime.ComponentUnitDiagnostic

//PerformComponentDiagnostics executes the diagnostic action for the provided components. If no components are provided,
// PerformComponentDiagnostics executes the diagnostic action for the provided components. If no components are provided,
// then it performs the diagnostics for all current units.
PerformComponentDiagnostics(ctx context.Context, additionalMetrics []cproto.AdditionalDiagnosticRequest, req ...component.Component) ([]runtime.ComponentDiagnostic, error)
}
Expand Down Expand Up @@ -198,8 +200,12 @@ type Coordinator struct {
// state should never be directly read or written outside the Coordinator
// goroutine. Callers who need to access or modify the state should use the
// public accessors like State(), SetLogLevel(), etc.
state State
stateBroadcaster *broadcaster.Broadcaster[State]
state State
stateBroadcaster *broadcaster.Broadcaster[State]

// If you get a race detector error while accessing this field, it probably
// means you're calling private Coordinator methods from outside the
// Coordinator goroutine.
stateNeedsRefresh bool

// overrideState is used during the update process to report the overall
Expand All @@ -210,6 +216,10 @@ type Coordinator struct {
// SetOverrideState helper to the Coordinator goroutine.
overrideStateChan chan *coordinatorOverrideState

// upgradeDetailsChan forwards upgrade details from the publicly accessible
// SetUpgradeDetails helper to the Coordinator goroutine.
upgradeDetailsChan chan *details.Details

// loglevelCh forwards log level changes from the public API (SetLogLevel)
// to the run loop in Coordinator's main goroutine.
logLevelCh chan logp.Level
Expand Down Expand Up @@ -332,8 +342,9 @@ func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.
// synchronization in the subscriber API, just set the input buffer to 0.
stateBroadcaster: broadcaster.New(state, 64, 32),

logLevelCh: make(chan logp.Level),
overrideStateChan: make(chan *coordinatorOverrideState),
logLevelCh: make(chan logp.Level),
overrideStateChan: make(chan *coordinatorOverrideState),
upgradeDetailsChan: make(chan *details.Details),
}
// Setup communication channels for any non-nil components. This pattern
// lets us transparently accept nil managers / simulated events during
Expand Down Expand Up @@ -425,7 +436,7 @@ func (c *Coordinator) ReExec(callback reexec.ShutdownCallbackFn, argOverrides ..
// Upgrade runs the upgrade process.
// Called from external goroutines.
func (c *Coordinator) Upgrade(ctx context.Context, version string, sourceURI string, action *fleetapi.ActionUpgrade, skipVerifyOverride bool, skipDefaultPgp bool, pgpBytes ...string) error {
// early check outside of upgrader before overridding the state
// early check outside of upgrader before overriding the state
if !c.upgradeMgr.Upgradeable() {
return ErrNotUpgradable
}
Expand Down Expand Up @@ -455,17 +466,33 @@ func (c *Coordinator) Upgrade(ctx context.Context, version string, sourceURI str

// override the overall state to upgrading until the re-execution is complete
c.SetOverrideState(agentclient.Upgrading, fmt.Sprintf("Upgrading to version %s", version))
cb, err := c.upgradeMgr.Upgrade(ctx, version, sourceURI, action, skipVerifyOverride, skipDefaultPgp, pgpBytes...)

// initialize upgrade details
actionID := ""
if action != nil {
actionID = action.ActionID
}
det := details.NewDetails(version, details.StateRequested, actionID)
det.RegisterObserver(c.SetUpgradeDetails)
det.RegisterObserver(c.logUpgradeDetails)

cb, err := c.upgradeMgr.Upgrade(ctx, version, sourceURI, action, det, skipVerifyOverride, skipDefaultPgp, pgpBytes...)
if err != nil {
c.ClearOverrideState()
det.Fail(err)
return err
}
if cb != nil {
det.SetState(details.StateRestarting)
c.ReExec(cb)
}
return nil
}

func (c *Coordinator) logUpgradeDetails(details *details.Details) {
c.logger.Infow("updated upgrade details", "upgrade_details", details)
}

// AckUpgrade is the method used on startup to ack a previously successful upgrade action.
// Called from external goroutines.
func (c *Coordinator) AckUpgrade(ctx context.Context, acker acker.Acker) error {
Expand Down Expand Up @@ -888,6 +915,9 @@ func (c *Coordinator) runLoopIteration(ctx context.Context) {
case overrideState := <-c.overrideStateChan:
c.setOverrideState(overrideState)

case upgradeDetails := <-c.upgradeDetailsChan:
c.setUpgradeDetails(upgradeDetails)

case componentState := <-c.managerChans.runtimeManagerUpdate:
// New component change reported by the runtime manager via
// Coordinator.watchRuntimeComponents(), merge it with the
Expand Down
Loading

0 comments on commit 0366ce4

Please sign in to comment.