Skip to content

Commit

Permalink
Merge pull request #147 from boxboat/feature-spire
Browse files Browse the repository at this point in the history
Feature spire
  • Loading branch information
adityasaky authored Nov 15, 2021
2 parents 952a6cf + 41e3cd9 commit 7f8ae9c
Show file tree
Hide file tree
Showing 29 changed files with 1,222 additions and 239 deletions.
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ARG GO_VERSION=1.17

FROM golang:${GO_VERSION}-alpine as build

RUN apk --no-cache add make
WORKDIR /src
COPY go.mod go.sum /src/
RUN go mod download
COPY . /src/
RUN make build

FROM gcr.io/distroless/base:debug AS debug
COPY --from=build /src/bin/in-toto /bin/in-toto
ENTRYPOINT [ "/bin/in-toto" ]

FROM gcr.io/distroless/base
COPY --from=build /src/bin/in-toto /bin/in-toto
ENTRYPOINT [ "/bin/in-toto" ]
57 changes: 45 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ ORGANIZATION := example
ROOT_DAYS := 3650
INTERMEDIATE_DAYS := 3650
LEAF_DAYS := 1
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)


# Template Locations
OPENSSL_TMPL := ./certs/openssl.cnf.tmpl
LAYOUT_TMPL := ./certs/layout.tmpl

build: modules
@mkdir -p bin
@go build -o ./bin/in-toto main.go
GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 go build \
-o ./bin/in-toto main.go

modules:
@go mod tidy

clean: clean-certs clean-test-files
clean: clean-certs clean-test-files spiffe-infra-down
@rm -rf ./bin

clean-certs:
Expand All @@ -30,37 +34,66 @@ clean-test-files:
@rm -rf ./untar.link
@rm -rf ./.srl

test: go-test test-verify
test: go-test test-verify test-spiffe-verify

go-test:
@go test ./...

test-sign: build generate_layout
# Running test-sign
@./bin/in-toto sign -f ./test/tmp/test.layout -k ./certs/example.com.layout.key.pem -o ./test/tmp/signed.layout
cd ./test/tmp; ../../bin/in-toto sign -f ./test.layout -k ../../certs/example.com.layout.key.pem -o ./signed.layout

test-record: build generate_layout
# Running record start
@./bin/in-toto record start -n write-code -c ./certs/example.com.write-code.cert.pem -k ./certs/example.com.write-code.key.pem -d ./test/tmp
cd ./test/tmp; ../../bin/in-toto record start -n write-code -c ../../certs/example.com.write-code.cert.pem -k ../../certs/example.com.write-code.key.pem -d .
# Record running step
@echo goodbye > ./test/tmp/foo.py
cd ./test/tmp; echo goodbye > foo.py
# Running record stop
@./bin/in-toto record stop -n write-code -c ./certs/example.com.write-code.cert.pem -p ./test/tmp/foo.py -k ./certs/example.com.write-code.key.pem -d ./test/tmp
cd ./test/tmp; ../../bin/in-toto record stop -n write-code -c ../../certs/example.com.write-code.cert.pem -p foo.py -k ../../certs/example.com.write-code.key.pem -d .

test-run: build generate_layout
# Running write code step
@./bin/in-toto run -n write-code -c ./certs/example.com.write-code.cert.pem -k ./certs/example.com.write-code.key.pem -p ./test/tmp/foo.py -d ./test/tmp -- /bin/sh -c "echo hello > ./test/tmp/foo.py"
cd ./test/tmp; ../../bin/in-toto run -n write-code -c ../../certs/example.com.write-code.cert.pem -k ../../certs/example.com.write-code.key.pem -p foo.py -d . -- sh -c "echo hello > foo.py"
# Running package step
@./bin/in-toto run -n package -c ./certs/example.com.package.cert.pem -k ./certs/example.com.package.key.pem -m ./test/tmp/foo.py -p ./test/tmp/foo.tar.gz -d ./test/tmp -- tar zcvf ./test/tmp/foo.tar.gz ./test/tmp/foo.py
cd ./test/tmp; ../../bin/in-toto run -n package -c ../../certs/example.com.package.cert.pem -k ../../certs/example.com.package.key.pem -m foo.py -p foo.tar.gz -d . -- tar zcvf foo.tar.gz foo.py

test-verify: test-sign test-run
# Running test verify
@./bin/in-toto verify -l ./test/tmp/signed.layout -k ./certs/example.com.layout.cert.pem -i ./certs/example.com.intermediate.cert.pem -d ./test/tmp
cd ./test/tmp; ../../bin/in-toto verify -l ./signed.layout -k ../../certs/example.com.layout.cert.pem -i ../../certs/example.com.intermediate.cert.pem -d .

test-spiffe-run: test-spiffe-sign
# Running write code step
docker exec -u 1000 -w /test/tmp -it intoto-runner in-toto run --spiffe-workload-api-path unix:///run/spire/sockets/agent.sock -n write-code -p foo.py -d . -- sh -c "echo hello > foo.py"
# Running package step
docker exec -u 1001 -w /test/tmp -it intoto-runner in-toto run --spiffe-workload-api-path unix:///run/spire/sockets/agent.sock -n package -m foo.py -p foo.tar.gz -d . -- tar zcvf foo.tar.gz foo.py

test-spiffe-verify: test-spiffe-sign test-spiffe-run
# Running test verify
docker exec -it -w /test/tmp intoto-runner /bin/in-toto verify -l ./spiffe.signed.layout -k ./layout-svid.pem -d .

test-spiffe-sign: build spiffe-test-generate-layout
docker exec -it -w /test/tmp intoto-runner /bin/in-toto sign -f ./spiffe.test.layout -k ./layout-key.pem -o ./spiffe.signed.layout

spiffe-test-generate-layout: spiffe-infra-up
# Get key layout from the root cert
$(eval rootca := $(shell ./bin/in-toto key layout ./test/tmp/layout-bundle.pem | sed -e 's/\\n/\\\\n/g'))
cat $(LAYOUT_TMPL) | sed -e 's#{{ROOTCA}}#$(rootca)#' > ./test/tmp/spiffe.test.layout
docker-compose -f ./test-infra/docker-compose.yaml up -d intoto-runner

spiffe-infra-up: build
@mkdir -p ./test/tmp
@chmod 777 ./test/tmp
./test-infra/infra-up.sh
./test-infra/mint-cert.sh layout

spiffe-infra-down:
./test-infra/infra-down.sh

generate_layout: leaf_certs
generate_layout: build leaf_certs
@mkdir -p ./test/tmp
# get key layout from the root cert
$(eval rootca := $(shell ./bin/in-toto key layout ./certs/root.cert.pem | sed -e 's/\\n/\\\\n/g'))
@cat $(LAYOUT_TMPL) | sed -e 's#{{ROOTCA}}#$(rootca)#' > ./test/tmp/test.layout
cat $(LAYOUT_TMPL) | sed -e 's#{{ROOTCA}}#$(rootca)#' > ./test/tmp/test.layout

root-cert:
# Generate root cert openssl conf file
Expand Down
113 changes: 60 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ func main() {
To run the demo, pull down the source code, install Go, and run `make test-verify`.
This will use openssl to generate a certificate chain.

To run the demo using Spire, pull down the source code, install Go and Docker, and run `make test-spiffe-verify`.

SPIFFE compliant Leaf certificates are generated with SVIDs corresponding to functionaries. These certificates are consumed by in-toto to sign link-meta data and the layout policy.

During the in-toto verification process, `certificate constraints` are checked to ensure the build step link meta-data was signed with the correct SVID.

## Building
Expand Down Expand Up @@ -115,36 +119,39 @@ Usage:
in-toto run [flags]
Flags:
-c, --cert string Path to a PEM formatted certificate that corresponds with
the provided key.
-e, --exclude stringArray Path patterns to match paths that should not be recorded as 0
‘materials’ or ‘products’. Passed patterns override patterns defined
in environment variables or config files. See Config docs for details.
-h, --help help for run
-k, --key string Path to a PEM formatted private key file used to sign
the resulting link metadata.
-l, --lstrip-paths stringArray Path prefixes used to left-strip artifact paths before storing
them to the resulting link metadata. If multiple prefixes
are specified, only a single prefix can match the path of
any artifact and that is then left-stripped. All prefixes
are checked to ensure none of them are a left substring
of another.
-m, --materials stringArray Paths to files or directories, whose paths and hashes
are stored in the resulting link metadata before the
command is executed. Symlinks are followed.
-d, --metadata-directory string Directory to store link metadata (default "./")
-n, --name string Name used to associate the resulting link metadata
with the corresponding step defined in an in-toto layout.
--normalize-line-endings Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.
-p, --products stringArray Paths to files or directories, whose paths and hashes
are stored in the resulting link metadata after the
command is executed. Symlinks are followed.
-r, --run-dir string runDir specifies the working directory of the command.
If runDir is the empty string, the command will run in the
calling process's current directory. The runDir directory must
exist, be writable, and not be a symlink.
-c, --cert string Path to a PEM formatted certificate that corresponds with
the provided key.
-e, --exclude stringArray path patterns to match paths that should not be recorded as 0
‘materials’ or ‘products’. Passed patterns override patterns defined
in environment variables or config files. See Config docs for details.
-h, --help help for run
-k, --key string Path to a PEM formatted private key file used to sign
the resulting link metadata. (passing one of '--key'
or '--gpg' is required)
-l, --lstrip-paths stringArray path prefixes used to left-strip artifact paths before storing
them to the resulting link metadata. If multiple prefixes
are specified, only a single prefix can match the path of
any artifact and that is then left-stripped. All prefixes
are checked to ensure none of them are a left substring
of another.
-m, --materials stringArray Paths to files or directories, whose paths and hashes
are stored in the resulting link metadata before the
command is executed. Symlinks are followed.
-n, --name string Name used to associate the resulting link metadata
with the corresponding step defined in an in-toto
layout.
--normalize-line-endings Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.
-d, --metadata-directory string directory to store link metadata (default "./")
-p, --products stringArray Paths to files or directories, whose paths and hashes
are stored in the resulting link metadata after the
command is executed. Symlinks are followed.
-r, --run-dir string runDir specifies the working directory of the command.
If runDir is the empty string, the command will run in the
calling process's current directory. The runDir directory must
exist, be writable, and not be a symlink.
--spiffe-workload-api-path string uds path for spiffe workload api
```

### sign
Expand Down Expand Up @@ -211,29 +218,29 @@ passed materials and signs it with the passed functionary’s key.
stop Records and adds the paths and hashes of the passed products to the link metadata file and updates the signature.
Flags:
-c, --cert string Path to a PEM formatted certificate that corresponds
with the provided key.
-e, --exclude stringArray Path patterns to match paths that should not be recorded as
‘materials’ or ‘products’. Passed patterns override patterns defined
in environment variables or config files. See Config docs for details.
-h, --help help for record
-k, --key string Path to a private key file to sign the resulting link metadata.
The keyid prefix is used as an infix for the link metadata filename,
i.e. ‘<name>.<keyid prefix>.link’. See ‘–key-type’ for available
formats. Passing one of ‘–key’ or ‘–gpg’ is required.
-l, --lstrip-paths stringArray Path prefixes used to left-strip artifact paths before storing
them to the resulting link metadata. If multiple prefixes
are specified, only a single prefix can match the path of
any artifact and that is then left-stripped. All prefixes
are checked to ensure none of them are a left substring
of another.
-d, --metadata-directory string Directory to store link metadata (default "./")
-n, --name string Name for the resulting link metadata file.
It is also used to associate the link with a step defined
in an in-toto layout.
--normalize-line-endings Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.
-c, --cert string Path to a PEM formatted certificate that corresponds with the provided key.
-e, --exclude stringArray Path patterns to match paths that should not be recorded as
‘materials’ or ‘products’. Passed patterns override patterns defined
in environment variables or config files. See Config docs for details.
-h, --help help for record
-k, --key string Path to a private key file to sign the resulting link metadata.
The keyid prefix is used as an infix for the link metadata filename,
i.e. ‘<name>.<keyid prefix>.link’. See ‘–key-type’ for available
formats. Passing one of ‘–key’ or ‘–gpg’ is required.
-l, --lstrip-paths stringArray Path prefixes used to left-strip artifact paths before storing
them to the resulting link metadata. If multiple prefixes
are specified, only a single prefix can match the path of
any artifact and that is then left-stripped. All prefixes
are checked to ensure none of them are a left substring
of another.
-d, --metadata-directory string directory to store link metadata (default "./")
-n, --name string name for the resulting link metadata file.
It is also used to associate the link with a step defined
in an in-toto layout.
--normalize-line-endings Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.
--spiffe-workload-api-path string uds path for spiffe workload api
Use "in-toto record [command] --help" for more information about a command.
```
Expand Down
12 changes: 6 additions & 6 deletions certs/layout.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"run": [
"tar",
"xfz",
"./test/tmp/foo.tar.gz"
"foo.tar.gz"
]
}
],
Expand All @@ -53,7 +53,7 @@
"_type": "step",
"cert_constraints": [
{
"common_name": "write-code.example.com",
"common_name": "*",
"dns_names": [
""
],
Expand All @@ -71,7 +71,7 @@
]
}
],
"expected_command": ["/bin/sh -c echo hello > ./test/tmp/foo.py"],
"expected_command": ["sh -c echo hello > foo.py"],
"expected_materials": [],
"expected_products": [
[
Expand All @@ -87,7 +87,7 @@
"_type": "step",
"cert_constraints": [
{
"common_name": "package.example.com",
"common_name": "*",
"dns_names": [
""
],
Expand All @@ -108,8 +108,8 @@
"expected_command": [
"tar",
"zcvf",
"./test/tmp/foo.tar.gz",
"./test/tmp/foo.py"
"foo.tar.gz",
"foo.py"
],
"expected_materials": [
[
Expand Down
59 changes: 17 additions & 42 deletions cmd/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

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

intoto "github.com/in-toto/in-toto-golang/in_toto"
Expand All @@ -23,7 +22,7 @@ var recordCmd = &cobra.Command{
evidence for supply chain steps that cannot be carried out by a single command
(for which ‘in-toto-run’ should be used). It returns a non-zero value on
failure and zero otherwise.`,
PersistentPreRunE: recordPreRun,
PersistentPreRunE: getKeyCert,
}

var recordStartCmd = &cobra.Command{
Expand Down Expand Up @@ -111,6 +110,22 @@ of another.`,
in environment variables or config files. See Config docs for details.`,
)

recordCmd.PersistentFlags().StringVar(
&spiffeUDS,
"spiffe-workload-api-path",
"",
"UDS path for SPIFFE workload API",
)

recordCmd.PersistentFlags().BoolVar(
&lineNormalization,
"normalize-line-endings",
false,
`Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.`,
)

recordCmd.MarkPersistentFlagRequired("name")

// Record Start Command
Expand Down Expand Up @@ -138,46 +153,6 @@ command is executed. Symlinks are followed.`,
are stored in the resulting link metadata after the
command is executed. Symlinks are followed.`,
)

recordCmd.Flags().BoolVar(
&lineNormalization,
"normalize-line-endings",
false,
`Enable line normalization in order to support different
operating systems. It is done by replacing all line separators
with a new line character.`,
)
}

func recordPreRun(cmd *cobra.Command, args []string) error {
key = intoto.Key{}
cert = intoto.Key{}

if keyPath == "" && certPath == "" {
return fmt.Errorf("key or cert must be provided")
}

if len(keyPath) > 0 {
if _, err := os.Stat(keyPath); err == nil {
if err := key.LoadKeyDefaults(keyPath); err != nil {
return fmt.Errorf("invalid key at %s: %w", keyPath, err)
}
} else {
return fmt.Errorf("key not found at %s: %w", keyPath, err)
}
}

if len(certPath) > 0 {
if _, err := os.Stat(certPath); err == nil {
if err := cert.LoadKeyDefaults(certPath); err != nil {
return fmt.Errorf("invalid cert at %s: %w", certPath, err)
}
key.KeyVal.Certificate = cert.KeyVal.Certificate
} else {
return fmt.Errorf("cert not found at %s: %w", certPath, err)
}
}
return nil
}

func recordStart(cmd *cobra.Command, args []string) error {
Expand Down
Loading

0 comments on commit 7f8ae9c

Please sign in to comment.