Skip to content

Commit

Permalink
Add basic policy checking
Browse files Browse the repository at this point in the history
  • Loading branch information
nsmith5 committed Jan 5, 2022
1 parent b392866 commit 96c1355
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 21 deletions.
24 changes: 19 additions & 5 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import (
)

type agent struct {
rc *rekor.Client
rc *rekor.Client
policies []policy

quit chan struct{}
}
Expand All @@ -22,9 +23,11 @@ func newAgent(c config) (*agent, error) {
return nil, err
}

policies := c.Policies

quit := make(chan struct{})

return &agent{rc, quit}, nil
return &agent{rc, policies, quit}, nil
}

// run starts off the agent. The call blocks or exits returning an error
Expand Down Expand Up @@ -65,9 +68,20 @@ func (a *agent) run() error {
// Incase we just recovered from a temporary outage, lets reset the backoff
currentBackoff = initialBackoff

// TODO: Do something with this log entry!
fmt.Printf("%#v\n", entry)
time.Sleep(5 * time.Second)
// Policy checks!
for _, p := range a.policies {
violation, err := p.allowed(entry)
if err != nil {
// huh... what to do here?
continue
}

if violation {
// TODO: Send to outputs!
fmt.Printf("Entry %#v violated policy %s\n", entry, p.Name)
time.Sleep(5 * time.Second)
}
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func runCLI(cmd *cobra.Command, args []string) {
os.Exit(1)
}

fmt.Printf("debug: config %#v\n", c)

a, err := newAgent(c)
if err != nil {
fmt.Println("Failed to initialize agent:", err)
Expand Down
3 changes: 2 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package main

type config struct {
RekorServerURL string `yaml:"rekorServerURL"`
RekorServerURL string `yaml:"rekorServerURL"`
Policies []policy `yaml:"policies"`
}
19 changes: 19 additions & 0 deletions etc/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
rekorServerURL: https://rekor.sigstore.dev
policies:
- name: x509-used
description: |-
Alerts if any x509 type key is used
body: |
package auth
default allow = false
allow {
format := input.spec.signature.format
format != "x509"
}
- name: allow-all
description: |-
Alerts on all entries
body: |
package auth
default allow = true
1 change: 0 additions & 1 deletion etc/example-config.yaml

This file was deleted.

9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@ go 1.17

require (
github.com/oklog/run v1.1.0
github.com/open-policy-agent/opa v0.36.0
github.com/spf13/cobra v1.3.0
github.com/spf13/viper v1.10.1
)

require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
Expand Down
131 changes: 128 additions & 3 deletions go.sum

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"context"

"github.com/nsmith5/rekor-sidekick/rekor"
"github.com/open-policy-agent/opa/rego"
)

type policy struct {
Name string
Description string
Body string
}

func (p policy) allowed(e rekor.LogEntry) (bool, error) {
r := rego.New(
rego.Query("data.auth.allow"),
rego.Module(p.Name, p.Body),
rego.Input(e),
)
rs, err := r.Eval(context.Background())
if err != nil {
return false, err
}
return rs.Allowed(), nil
}
88 changes: 88 additions & 0 deletions policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"testing"

"github.com/nsmith5/rekor-sidekick/rekor"
)

func TestPolicy(t *testing.T) {
tests := map[policy]struct {
Allow []rekor.LogEntry
Deny []rekor.LogEntry
}{
policy{
Name: `allow-all`,
Description: ``,
Body: "package auth\ndefault allow = true",
}: {
Allow: []rekor.LogEntry{
rekor.LogEntry{
"spec": map[string]interface{}{
"foo": "bar",
},
},
rekor.LogEntry{},
},
Deny: []rekor.LogEntry{},
},
policy{
Name: `only x509 signature`,
Description: ``,
Body: `package auth
default auth = false
allow {
format := input.spec.signature.format
format == "x509"
}`,
}: {
Allow: []rekor.LogEntry{
rekor.LogEntry{
"spec": map[string]interface{}{
"signature": map[string]interface{}{
"format": "x509",
},
},
},
},
Deny: []rekor.LogEntry{
rekor.LogEntry{
"spec": map[string]interface{}{
"signature": map[string]interface{}{
"format": "minisign",
},
},
},
},
},
}

for p, data := range tests {
t.Run(p.Name, func(t *testing.T) {
for _, entry := range data.Allow {
violation, err := p.allowed(entry)
if err != nil {
t.Errorf("policy %s failed to check allowed entry with error %s", p.Name, err)
continue
}
if !violation {
t.Errorf("policy %s denied entry which was expected to be allowed", p.Name)
}

}

for _, entry := range data.Deny {
violation, err := p.allowed(entry)
if err != nil {
t.Errorf("policy %s failed to check allowed entry with error %s", p.Name, err)
continue
}
if violation {
t.Errorf("policy %s allowed entry which was expected to be denied", p.Name)
}

}

})
}
}
14 changes: 5 additions & 9 deletions rekor/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ var (
)

// LogEntry is a Rekor log entry
type LogEntry struct {
Kind string
APIVersion string `json:"apiVersion"`
Spec interface{}
}
type LogEntry map[string]interface{}

// treeState represents the current state of the transparency log (size
// etc)
Expand Down Expand Up @@ -60,7 +56,7 @@ func NewClient(baseURL string) (*Client, error) {
return &rc, nil
}

func (rc *Client) getLogEntry(index uint) (*LogEntry, error) {
func (rc *Client) getLogEntry(index uint) (LogEntry, error) {
url := fmt.Sprintf("%s/api/v1/log/entries?logIndex=%d", rc.baseURL, index)

req, err := http.NewRequest(`GET`, url, nil)
Expand Down Expand Up @@ -99,20 +95,20 @@ func (rc *Client) getLogEntry(index uint) (*LogEntry, error) {
break
}

var entry LogEntry
var entry = make(LogEntry)
err = json.NewDecoder(
base64.NewDecoder(base64.URLEncoding, strings.NewReader(body)),
).Decode(&entry)
if err != nil {
return nil, err
}

return &entry, nil
return entry, nil
}

// GetNextLogEntry pulls the next entry in the Rekor log. If the
// next log doesn't exist yet ErrEntryDoesntExist is returned.
func (rc *Client) GetNextLogEntry() (*LogEntry, error) {
func (rc *Client) GetNextLogEntry() (LogEntry, error) {
entry, err := rc.getLogEntry(rc.currentIndex)
if err != nil {
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions rekor/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ func TestGetLogEntry(t *testing.T) {
t.Fatal(err)
}

if entry.Kind != `rekord` {
if kind := entry["kind"].(string); kind != `rekord` {
t.Error(`expected rekord type`)
}
if entry.APIVersion != `0.0.1` {
if version := entry["apiVersion"].(string); version != `0.0.1` {
t.Error(`expected api version 0.0.1`)
}
}
Expand Down

0 comments on commit 96c1355

Please sign in to comment.