Skip to content
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
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: release

on:
push:
# run only against tags
tags:
- "*"

permissions:
contents: write
# packages: write
# issues: write

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v4
with:
go-version: '1.21.3'
- uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ bin/
.idea
*.log
tmp/

dist/
39 changes: 39 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
main: ./cmd/secops-chaos
goos:
- linux
- windows
- darwin
ldflags:
- "-X github.com/operantai/secops-chaos/cmd/secops-chaos/cmd.GitCommit={{.Commit}}"
- "-X github.com/operantai/secops-chaos/cmd/secops-chaos/cmd.Version={{.Version}}"
- "-X github.com/operantai/secops-chaos/cmd/secops-chaos/cmd.BuildDate={{ .Date }}"

archives:
- format: tar.gz
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@

### Installation

``` sh
go install github.com/operantai/secops-chaos/cmd/secops-chaos@latest
```
You can fetch the latest release [here][latest-release-url], or you can build from source.

#### Building from Source

Go will automatically install it in your `$GOPATH/bin` directory, which should be in your `$PATH`.
To build from source, you'll need to have [Go](https://golang.org/) installed.

```sh
git clone https://github.com/operantai/secops-chaos
cd secops-chaos
make build
```

### Usage

Expand Down Expand Up @@ -69,6 +75,7 @@ Please read the contribution guidelines, [here][contributing-url].

Distributed under the [Apache License 2.0][license-url].

[latest-release-url]: https://github.com/operantai/secops-chaos/releases/latest
[experiments-dir-url]: https://github.com/operantai/secops-chaos/blob/main/experiments
[contributing-url]: https://github.com/operantai/secops-chaos/blob/main/CONTRIBUTING.md
[license-url]: https://github.com/operantai/secops-chaos/blob/main/LICENSE
8 changes: 4 additions & 4 deletions experiments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ type Experiment interface {
// Technique returns the attack method
Technique() string
// Run runs the experiment, returning an error if it fails
Run(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error
Run(ctx context.Context, client *k8s.client, experimentConfig *ExperimentConfig) error
// Verify verifies the experiment, returning an error if it fails
Verify(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) (*Outcome, error)
Verify(ctx context.Context, client *k8s.client, experimentConfig *ExperimentConfig) (*Outcome, error)
// Cleanup cleans up the experiment, returning an error if it fails
Cleanup(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error
Cleanup(ctx context.Context, client *k8s.client, experimentConfig *ExperimentConfig) error
}
```

Expand Down Expand Up @@ -88,7 +88,7 @@ type HostPath struct {
Path string `yaml:"path"`
}

func (p *HostPathMountExperimentConfig) Run(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error {
func (p *HostPathMountExperimentConfig) Run(ctx context.Context, client *k8s.client, experimentConfig *ExperimentConfig) error {
var hostPathMountExperimentConfig HostPathMountExperimentConfig
yamlObj, _ := yaml.Marshal(experimentConfig)
err := yaml.Unmarshal(yamlObj, &hostPathMountExperimentConfig)
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ go 1.21.3

require (
github.com/charmbracelet/lipgloss v0.9.1
github.com/mitchellh/mapstructure v1.5.0
github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.4
gopkg.in/yaml.v3 v3.0.1
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
18 changes: 10 additions & 8 deletions internal/experiments/experiments.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/operantai/secops-chaos/internal/k8s"
"github.com/operantai/secops-chaos/internal/output"
"github.com/operantai/secops-chaos/internal/verifier"
"k8s.io/client-go/kubernetes"
)

// Experiment is the interface for an experiment
Expand All @@ -25,17 +24,17 @@ type Experiment interface {
// Technique returns the attack method
Technique() string
// Run runs the experiment, returning an error if it fails
Run(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error
Run(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) error
// Verify verifies the experiment, returning an error if it fails
Verify(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) (*verifier.Outcome, error)
Verify(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) (*verifier.Outcome, error)
// Cleanup cleans up the experiment, returning an error if it fails
Cleanup(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error
Cleanup(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) error
}

// Runner runs a set of experiments
type Runner struct {
ctx context.Context
client *kubernetes.Clientset
client *k8s.Client
experiments map[string]Experiment
experimentsConfig map[string]*ExperimentConfig
}
Expand Down Expand Up @@ -73,8 +72,11 @@ func NewRunner(ctx context.Context, experimentFiles []string) *Runner {
}

return &Runner{
ctx: ctx,
client: client,
ctx: ctx,
client: &k8s.Client{
Clientset: client.Clientset,
RestConfig: client.RestConfig,
},
experiments: experimentMap,
experimentsConfig: experimentConfigMap,
}
Expand Down Expand Up @@ -118,7 +120,7 @@ func (r *Runner) RunVerifiers(writeJSON bool) {

// if JSON flag is set, print JSON output
if writeJSON {
k8sVersion, err := k8s.GetK8sVersion(r.client)
k8sVersion, err := k8s.GetK8sVersion(r.client.Clientset)
if err != nil {
output.WriteError("Failed to get Kubernetes version: %s", err)
}
Expand Down
25 changes: 14 additions & 11 deletions internal/experiments/experiments_cluster_admin_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"context"

"github.com/operantai/secops-chaos/internal/categories"
"github.com/operantai/secops-chaos/internal/k8s"
"github.com/operantai/secops-chaos/internal/verifier"

"gopkg.in/yaml.v3"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/utils/pointer"
)

Expand Down Expand Up @@ -45,7 +45,7 @@ func (p *ClusterAdminBindingExperimentConfig) Framework() string {
return string(categories.Mitre)
}

func (p *ClusterAdminBindingExperimentConfig) Run(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error {
func (p *ClusterAdminBindingExperimentConfig) Run(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) error {
var config ClusterAdminBindingExperimentConfig
yamlObj, err := yaml.Marshal(experimentConfig)
if err != nil {
Expand All @@ -66,7 +66,8 @@ func (p *ClusterAdminBindingExperimentConfig) Run(ctx context.Context, client *k
},
}

_, err = client.CoreV1().ServiceAccounts(config.Metadata.Namespace).Create(ctx, sa, metav1.CreateOptions{})
clientset := client.Clientset
_, err = clientset.CoreV1().ServiceAccounts(config.Metadata.Namespace).Create(ctx, sa, metav1.CreateOptions{})
if err != nil {
return err
}
Expand All @@ -92,7 +93,7 @@ func (p *ClusterAdminBindingExperimentConfig) Run(ctx context.Context, client *k
},
}

_, err = client.RbacV1().ClusterRoleBindings().Create(ctx, clusterRoleBinding, metav1.CreateOptions{})
_, err = clientset.RbacV1().ClusterRoleBindings().Create(ctx, clusterRoleBinding, metav1.CreateOptions{})
if err != nil {
return err
}
Expand Down Expand Up @@ -136,11 +137,11 @@ func (p *ClusterAdminBindingExperimentConfig) Run(ctx context.Context, client *k
},
},
}
_, err = client.AppsV1().Deployments(config.Metadata.Namespace).Create(ctx, deployment, metav1.CreateOptions{})
_, err = clientset.AppsV1().Deployments(config.Metadata.Namespace).Create(ctx, deployment, metav1.CreateOptions{})
return err
}

func (p *ClusterAdminBindingExperimentConfig) Verify(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) (*verifier.Outcome, error) {
func (p *ClusterAdminBindingExperimentConfig) Verify(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) (*verifier.Outcome, error) {
var config ClusterAdminBindingExperimentConfig
yamlObj, _ := yaml.Marshal(experimentConfig)
err := yaml.Unmarshal(yamlObj, &config)
Expand All @@ -160,7 +161,8 @@ func (p *ClusterAdminBindingExperimentConfig) Verify(ctx context.Context, client
LabelSelector: "experiment=" + config.Metadata.Name,
}

pods, err := client.CoreV1().Pods(config.Metadata.Namespace).List(ctx, listOptions)
clientset := client.Clientset
pods, err := clientset.CoreV1().Pods(config.Metadata.Namespace).List(ctx, listOptions)
if err != nil {
return nil, err
}
Expand All @@ -181,24 +183,25 @@ func (p *ClusterAdminBindingExperimentConfig) Verify(ctx context.Context, client
return v.GetOutcome(), nil
}

func (p *ClusterAdminBindingExperimentConfig) Cleanup(ctx context.Context, client *kubernetes.Clientset, experimentConfig *ExperimentConfig) error {
func (p *ClusterAdminBindingExperimentConfig) Cleanup(ctx context.Context, client *k8s.Client, experimentConfig *ExperimentConfig) error {
var config ClusterAdminBindingExperimentConfig
yamlObj, _ := yaml.Marshal(experimentConfig)
err := yaml.Unmarshal(yamlObj, &config)
if err != nil {
return err
}

err = client.AppsV1().Deployments(config.Metadata.Namespace).Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
clientset := client.Clientset
err = clientset.AppsV1().Deployments(config.Metadata.Namespace).Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
if err != nil {
return err
}
err = client.RbacV1().ClusterRoleBindings().Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
err = clientset.RbacV1().ClusterRoleBindings().Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
if err != nil {
return err
}

err = client.CoreV1().ServiceAccounts(config.Metadata.Namespace).Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
err = clientset.CoreV1().ServiceAccounts(config.Metadata.Namespace).Delete(ctx, config.Metadata.Name, metav1.DeleteOptions{})
if err != nil {
return err
}
Expand Down
Loading