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

Allow to build windows binaries #61

Merged
merged 4 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
vendor
/spiffe-helper
/spiffe-helper*
/artifacts
/releases
rpm/*.rpm
Expand Down
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.19.5
1.20.1
31 changes: 24 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ os2=osx
else ifeq ($(os1),Linux)
os1=linux
os2=linux
else ifeq (,$(findstring MYSYS_NT-10-0-, $(os1)))
os1=windows
os2=windows
else
$(error unsupported OS: $(os1))
endif
Expand All @@ -76,11 +79,18 @@ build_dir := $(DIR)/.build/$(os1)-$(arch1)

go_version := $(shell cat .go-version)
go_dir := $(build_dir)/go/$(go_version)
go_bin_dir := $(go_dir)/bin
go_url = https://storage.googleapis.com/golang/go$(go_version).$(os1)-$(arch2).tar.gz
go := PATH="$(go_bin_dir):$(PATH)" go
ifeq ($(os1),windows)
go_bin_dir = $(go_dir)/go/bin
go_url = https://storage.googleapis.com/golang/go$(go_version).$(os1)-$(arch2).zip
exe=".exe"
else
faisal-memon marked this conversation as resolved.
Show resolved Hide resolved
go_bin_dir = $(go_dir)/bin
go_url = https://storage.googleapis.com/golang/go$(go_version).$(os1)-$(arch2).tar.gz
exe=
endif
go_path := PATH="$(go_bin_dir):$(PATH)"

golangci_lint_version = v1.50.1
golangci_lint_version = v1.51.1
golangci_lint_dir = $(build_dir)/golangci_lint/$(golangci_lint_version)
golangci_lint_bin = $(golangci_lint_dir)/golangci-lint
golangci_lint_cache = $(golangci_lint_dir)/cache
Expand All @@ -90,7 +100,14 @@ golangci_lint_cache = $(golangci_lint_dir)/cache
############################################################################

go-check:
ifneq (go$(go_version), $(shell $(go) version 2>/dev/null | cut -f3 -d' '))
ifeq (go$(go_version), $(shell $(go_path) go version 2>/dev/null | cut -f3 -d' '))
else ifeq ($(os1),windows)
@echo "Installing go$(go_version)..."
$(E)rm -rf $(dir $(go_dir))
$(E)mkdir -p $(go_dir)
$(E)curl -o $(go_dir)\go.zip -sSfL $(go_url)
$(E)unzip -qq $(go_dir)\go.zip -d $(go_dir)
else
@echo "Installing go$(go_version)..."
$(E)rm -rf $(dir $(go_dir))
$(E)mkdir -p $(go_dir)
Expand Down Expand Up @@ -130,7 +147,7 @@ endif

.PHONY: tidy tidy-check lint lint-code
tidy: | go-check
$(E)$(go) mod tidy
$(E)$(go_path) mod tidy

tidy-check:
ifneq ($(git_dirty),)
Expand All @@ -153,7 +170,7 @@ lint-code: $(golangci_lint_bin) | go-check
.PHONY: build test clean distclean artifact tarball rpm

build: | go-check
go build -o spiffe-helper ./cmd/spiffe-helper
go build -o spiffe-helper${exe} ./cmd/spiffe-helper

artifact: tarball rpm

Expand Down
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@

The SPIFFE Helper is a simple utility for fetching X.509 SVID certificates from the SPIFFE Workload API, launch a process that makes use of the certificates and continuously get new certificates before they expire. The launched process is signaled to reload the certificates when is needed.

### Usage
## Usage
`$ spiffe-helper -config <config_file>`

`<config_file>`: file path to the configuration file.

If `-config` is not specified, the default value `helper.conf` is assumed.

### Configuration
## Configuration
The configuration file is an [HCL](https://github.com/hashicorp/hcl) formatted file that defines the following configurations:

|Configuration | Description | Example Value |
|--------------------------|------------------------------------------------------------------------------------------------| ------------- |
|`agentAddress` | Socket address of SPIRE Agent. | `"/tmp/agent.sock"` |
faisal-memon marked this conversation as resolved.
Show resolved Hide resolved
|`cmd` | The path to the process to launch. | `"ghostunnel"` |
|`cmdArgs` | The arguments of the process to launch. | `"server --listen localhost:8002 --target localhost:8001--keystore certs/svid_key.pem --cacert certs/svid_bundle.pem --allow-uri-san spiffe://example.org/Database"` |
|`certDir` | Directory name to store the fetched certificates. This directory must be created previously. | `"certs"` |
|`addIntermediatesToBundle`| Add intermediate certificates into Bundle file instead of SVID file. | `true` |
|`renewSignal` | The signal that the process to be launched expects to reload the certificates. | `"SIGUSR1"` |
|`svidFileName` | File name to be used to store the X.509 SVID public certificate in PEM format. | `"svid.pem"` |
|`svidKeyFileName` | File name to be used to store the X.509 SVID private key and public certificate in PEM format. | `"svid_key.pem"` |
|`svidBundleFileName` | File name to be used to store the X.509 SVID Bundle in PEM format. | `"svid_bundle.pem"` |

#### Configuration example
|`agentAddress` | Socket address of SPIRE Agent. | `"/tmp/agent.sock"` |
|`cmd` | The path to the process to launch. | `"ghostunnel"` |
|`cmdArgs` | The arguments of the process to launch. | `"server --listen localhost:8002 --target localhost:8001--keystore certs/svid_key.pem --cacert certs/svid_bundle.pem --allow-uri-san spiffe://example.org/Database"` |
|`certDir` | Directory name to store the fetched certificates. This directory must be created previously. | `"certs"` |
|`addIntermediatesToBundle`| Add intermediate certificates into Bundle file instead of SVID file. | `true` |
|`renewSignal` | The signal that the process to be launched expects to reload the certificates. It is not supported on Windows. | `"SIGUSR1"` |
|`svidFileName` | File name to be used to store the X.509 SVID public certificate in PEM format. | `"svid.pem"` |
|`svidKeyFileName` | File name to be used to store the X.509 SVID private key and public certificate in PEM format. | `"svid_key.pem"` |
|`svidBundleFileName` | File name to be used to store the X.509 SVID Bundle in PEM format. | `"svid_bundle.pem"` |

### Configuration example
```
agentAddress = "/tmp/agent.sock"
cmd = "ghostunnel"
Expand All @@ -39,3 +39,11 @@ svidFileName = "svid.pem"
svidKeyFileName = "svid_key.pem"
svidBundleFileName = "svid_bundle.pem"
```

### Windows example

agentAddress = "spire-agent\\public\\api"
certDir = "certs"
svidFileName = "svid.pem"
svidKeyFileName = "svid_key.pem"
svidBundleFileName = "svid_bundle.pem"
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/spiffe/spiffe-helper

go 1.19
go 1.20

require (
github.com/hashicorp/hcl v1.0.0
Expand Down
11 changes: 11 additions & 0 deletions helper_windows.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
agentAddress = "spire-agent\\public\\api"
cmd = ""
cmdArgs = ""
certDir = "certs"
svidFileName = "svid.pem"
svidKeyFileName = "svid_key.pem"
svidBundleFileName = "svid_bundle.pem"
# Add CA with intermediates into Bundle file instead of SVID file,
# it is the expected behavior in some scenarios like MySQL.
# Default: false
# addIntermediatesToBundle = false
4 changes: 4 additions & 0 deletions pkg/sidecar/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func ParseConfig(file string) (*Config, error) {
}

func ValidateConfig(c *Config) error {
if err := validateOSConfig(c); err != nil {
return err
}

switch {
case c.AgentAddress == "":
return errors.New("agentAddress is required")
Expand Down
27 changes: 2 additions & 25 deletions pkg/sidecar/sidecar.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package sidecar

import (
"context"
"crypto/x509"
"encoding/csv"
"encoding/pem"
"errors"
"fmt"
"os"
"os/exec"
Expand All @@ -15,7 +13,6 @@ import (

"github.com/spiffe/go-spiffe/v2/logger"
"github.com/spiffe/go-spiffe/v2/workloadapi"
"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand Down Expand Up @@ -62,19 +59,6 @@ func New(configPath string, log logger.Logger) (*Sidecar, error) {
}, nil
}

// RunDaemon starts the main loop
// Starts the workload API client to listen for new SVID updates
// When a new SVID is received on the updateChan, the SVID certificates
// are stored in disk and a restart signal is sent to the proxy's process
func (s *Sidecar) RunDaemon(ctx context.Context) error {
err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithAddr("unix://"+s.config.AgentAddress))
if err != nil && !errors.Is(err, context.Canceled) {
return err
}

return nil
}

// CertReadyChan returns a channel to know when the certificates are ready
func (s *Sidecar) CertReadyChan() <-chan struct{} {
return s.certReadyChan
Expand Down Expand Up @@ -122,15 +106,8 @@ func (s *Sidecar) signalProcess() (err error) {
s.process = cmd.Process
go s.checkProcessExit()
} else {
// Signal to reload certs
sig := unix.SignalNum(s.config.RenewSignal)
if sig == 0 {
return fmt.Errorf("error getting signal: %v", s.config.RenewSignal)
}

err = s.process.Signal(sig)
if err != nil {
return fmt.Errorf("error signaling process with signal: %v\n%w", sig, err)
if err := s.SignalProcess(); err != nil {
return err
}
}

Expand Down
45 changes: 45 additions & 0 deletions pkg/sidecar/util_posix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//go:build !windows
// +build !windows

package sidecar

import (
"context"
"errors"
"fmt"

"github.com/spiffe/go-spiffe/v2/workloadapi"
"golang.org/x/sys/unix"
)

// RunDaemon starts the main loop
// Starts the workload API client to listen for new SVID updates
// When a new SVID is received on the updateChan, the SVID certificates
// are stored in disk and a restart signal is sent to the proxy's process
func (s *Sidecar) RunDaemon(ctx context.Context) error {
err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithAddr("unix://"+s.config.AgentAddress))
if err != nil && !errors.Is(err, context.Canceled) {
return err
}

return nil
}

func (s *Sidecar) SignalProcess() error {
// Signal to reload certs
sig := unix.SignalNum(s.config.RenewSignal)
if sig == 0 {
return fmt.Errorf("error getting signal: %v", s.config.RenewSignal)
}

err := s.process.Signal(sig)
if err != nil {
return fmt.Errorf("error signaling process with signal: %v\n%w", sig, err)
}

return nil
}

func validateOSConfig(c *Config) error {
return nil
}
38 changes: 38 additions & 0 deletions pkg/sidecar/util_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build windows
// +build windows

package sidecar

import (
"context"
"errors"

"github.com/spiffe/go-spiffe/v2/workloadapi"
)

// RunDaemon starts the main loop
// Starts the workload API client to listen for new SVID updates
// When a new SVID is received on the updateChan, the SVID certificates
// are stored in disk and a restart signal is sent to the proxy's process
func (s *Sidecar) RunDaemon(ctx context.Context) error {
err := workloadapi.WatchX509Context(ctx, &x509Watcher{sidecar: s}, workloadapi.WithNamedPipeName(s.config.AgentAddress))
if err != nil && !errors.Is(err, context.Canceled) {
return err
}

return nil
}

func (s *Sidecar) SignalProcess() error {
// Signal to reload certs
// TODO: it is not possible to get signal by name on windows,
// we must provide int here
return errors.New("sending signal is not supported on windows")
}
faisal-memon marked this conversation as resolved.
Show resolved Hide resolved

func validateOSConfig(c *Config) error {
if c.RenewSignal != "" {
return errors.New("sending signals is not supported on windows")
}
return nil
}