Removed all(?) enterprise licensed code

This commit is contained in:
Laszlo Fogas 2019-04-03 20:15:52 +02:00
parent 768ed784bd
commit 2fbaa56eee
9 changed files with 0 additions and 715 deletions

View file

@ -1,48 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package secrets
import (
"github.com/drone/drone/model"
"github.com/drone/drone/store"
)
// NewDefault returns the Store wrapped as a Service.
func NewDefault(store store.Store) model.SecretService {
return New(store)
}
// Plugin defines the required interface for implementing a remote
// secret plugin and sourcing secrets from an external source.
type Plugin interface {
SecretListBuild(*model.Repo, *model.Build) ([]*model.Secret, error)
}
// Extend exetends the base secret service with the plugin.
func Extend(base model.SecretService, with Plugin) model.SecretService {
return &extender{base, with}
}
type extender struct {
model.SecretService
plugin Plugin
}
// extends the base secret service and combines the secret list with the
// secret list returned by the plugin.
func (e *extender) SecretListBuild(repo *model.Repo, build *model.Build) ([]*model.Secret, error) {
base, err := e.SecretService.SecretListBuild(repo, build)
if err != nil {
return nil, err
}
with, err := e.plugin.SecretListBuild(repo, build)
if err != nil {
return nil, err
}
for _, secret := range base {
with = append(with, secret)
}
return with, nil
}

View file

@ -1,68 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package secrets
import (
"testing"
"github.com/drone/drone/model"
)
func TestExtends(t *testing.T) {
base := &mocker{}
base.list = []*model.Secret{
{Name: "foo"},
{Name: "bar"},
}
with := &mocker{}
with.list = []*model.Secret{
{Name: "baz"},
{Name: "qux"},
}
extended := Extend(base, with)
list, err := extended.SecretListBuild(nil, nil)
if err != nil {
t.Errorf("Expected combined secret list, got error %q", err)
}
if got, want := list[0], with.list[0]; got != want {
t.Errorf("Expected correct precedence. Want %s, got %s", want.Name, got.Name)
}
if got, want := list[1], with.list[1]; got != want {
t.Errorf("Expected correct precedence. Want %s, got %s", want.Name, got.Name)
}
if got, want := list[2], base.list[0]; got != want {
t.Errorf("Expected correct precedence. Want %s, got %s", want.Name, got.Name)
}
if got, want := list[3], base.list[1]; got != want {
t.Errorf("Expected correct precedence. Want %s, got %s", want.Name, got.Name)
}
}
type mocker struct {
list []*model.Secret
error error
}
func (m *mocker) SecretFind(*model.Repo, string) (*model.Secret, error) {
return nil, nil
}
func (m *mocker) SecretList(*model.Repo) ([]*model.Secret, error) {
return nil, nil
}
func (m *mocker) SecretListBuild(*model.Repo, *model.Build) ([]*model.Secret, error) {
return m.list, m.error
}
func (m *mocker) SecretCreate(*model.Repo, *model.Secret) error {
return nil
}
func (m *mocker) SecretUpdate(*model.Repo, *model.Secret) error {
return nil
}
func (m *mocker) SecretDelete(*model.Repo, string) error {
return nil
}

View file

@ -1 +0,0 @@
fakeJwt

View file

@ -1,48 +0,0 @@
package vault
import (
"fmt"
"github.com/drone/drone/plugins/internal"
"io/ioutil"
"time"
)
/*
Vault JSON Response
{
"auth": {
"client_token" = "token",
"lease_duration" = 1234
}
}
*/
type vaultAuth struct {
Token string `json:"client_token"`
Lease int `json:"lease_duration"`
}
type vaultResp struct {
Auth vaultAuth
}
func getKubernetesToken(addr, role, mount, tokenFile string) (string, time.Duration, error) {
b, err := ioutil.ReadFile(tokenFile)
if err != nil {
return "", 0, err
}
var resp vaultResp
path := fmt.Sprintf("%s/v1/auth/%s/login", addr, mount)
data := map[string]string{
"jwt": string(b),
"role": role,
}
err = internal.Send("POST", path, data, &resp)
if err != nil {
return "", 0, err
}
ttl := time.Duration(resp.Auth.Lease) * time.Second
return resp.Auth.Token, ttl, nil
}

View file

@ -1,69 +0,0 @@
package vault
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"time"
)
func TestGetKubernetesToken(t *testing.T) {
fakeRole := "fakeRole"
fakeMountPoint := "kubernetes"
fakeJwtFile := "fixtures/fakeJwt"
b, _ := ioutil.ReadFile(fakeJwtFile)
fakeJwt := string(b)
fakeClientToken := "fakeClientToken"
fakeLeaseSeconds := 86400
fakeLeaseDuration := time.Duration(fakeLeaseSeconds) * time.Second
fakeResp := fmt.Sprintf("{\"auth\": {\"client_token\": \"%s\", \"lease_duration\": %d}}", fakeClientToken, fakeLeaseSeconds)
expectedPath := "/v1/auth/kubernetes/login"
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if r.Method != "POST" {
t.Errorf("Expected 'POST' request, got '%s'", r.Method)
}
if r.URL.EscapedPath() != expectedPath {
t.Errorf("Expected request to '%s', got '%s'", expectedPath, r.URL.EscapedPath())
}
var postdata struct {
Jwt string
Role string
}
err := json.NewDecoder(r.Body).Decode(&postdata)
if err != nil {
t.Errorf("Encountered error parsing request JSON: %s", err)
}
jwt := postdata.Jwt
if jwt != fakeJwt {
t.Errorf("Expected request to have jwt with value '%s', got: '%s'", fakeJwt, jwt)
}
role := postdata.Role
if role != fakeRole {
t.Errorf("Expected request to have role with value '%s', got: '%s'", fakeRole, role)
}
fmt.Fprintf(w, fakeResp)
}))
defer ts.Close()
url := ts.URL
token, ttl, err := getKubernetesToken(url, fakeRole, fakeMountPoint, fakeJwtFile)
if err != nil {
t.Errorf("getKubernetesToken returned an error: %s", err)
}
if token != fakeClientToken {
t.Errorf("Expected returned token to have value '%s', got: '%s'", fakeClientToken, token)
}
if ttl != fakeLeaseDuration {
t.Errorf("Expected TTL to have value '%s', got: '%s'", fakeLeaseDuration.Seconds(), ttl.Seconds())
}
}

View file

@ -1,45 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package vault
import "time"
// Opts sets custom options for the vault client.
type Opts func(v *vault)
// WithTTL returns an options that sets a TTL used to
// refresh periodic tokens.
func WithTTL(d time.Duration) Opts {
return func(v *vault) {
v.ttl = d
}
}
// WithRenewal returns an options that sets the renewal
// period used to refresh periodic tokens
func WithRenewal(d time.Duration) Opts {
return func(v *vault) {
v.renew = d
}
}
// WithAuth returns an options that sets the vault
// method to use for authentication
func WithAuth(method string) Opts {
return func(v *vault) {
v.auth = method
}
}
// WithKubernetes returns an options that sets
// kubernetes-auth parameters required to retrieve
// an initial vault token
func WithKubernetesAuth(addr, role, mount string) Opts {
return func(v *vault) {
v.kubeAuth.addr = addr
v.kubeAuth.role = role
v.kubeAuth.mount = mount
}
}

View file

@ -1,56 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package vault
import (
"testing"
"time"
)
func TestWithTTL(t *testing.T) {
v := new(vault)
opt := WithTTL(time.Hour)
opt(v)
if got, want := v.ttl, time.Hour; got != want {
t.Errorf("Want ttl %v, got %v", want, got)
}
}
func TestWithRenewal(t *testing.T) {
v := new(vault)
opt := WithRenewal(time.Hour)
opt(v)
if got, want := v.renew, time.Hour; got != want {
t.Errorf("Want renewal %v, got %v", want, got)
}
}
func TestWithAuth(t *testing.T) {
v := new(vault)
method := "kubernetes"
opt := WithAuth(method)
opt(v)
if got, want := v.auth, method; got != want {
t.Errorf("Want auth %v, got %v", want, got)
}
}
func TestWithKubernetesAuth(t *testing.T) {
v := new(vault)
addr := "https://address.fake"
role := "fakeRole"
mount := "kubernetes"
opt := WithKubernetesAuth(addr, role, mount)
opt(v)
if got, want := v.kubeAuth.addr, addr; got != want {
t.Errorf("Want addr %v, got %v", want, got)
}
if got, want := v.kubeAuth.role, role; got != want {
t.Errorf("Want role %v, got %v", want, got)
}
if got, want := v.kubeAuth.mount, mount; got != want {
t.Errorf("Want mount %v, got %v", want, got)
}
}

View file

@ -1,272 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package vault
import (
"errors"
"path"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/drone/drone/model"
"github.com/drone/drone/plugins/secrets"
"github.com/hashicorp/vault/api"
"gopkg.in/yaml.v2"
)
// yaml configuration representation
//
// secrets:
// docker_username:
// file: path/to/docker/username
// docker_password:
// file: path/to/docker/password
//
type vaultConfig struct {
Secrets map[string]struct {
Driver string
DriverOpts struct {
Path string
Key string
} `yaml:"driver_opts"`
// deprecated. do not use.
Vault string
Path string
File string
}
}
type vault struct {
store model.ConfigStore
client *api.Client
ttl time.Duration
renew time.Duration
auth string
kubeAuth kubeAuth
done chan struct{}
}
type kubeAuth struct {
addr, role, mount string
}
// New returns a new store with secrets loaded from vault.
func New(store model.ConfigStore, opts ...Opts) (secrets.Plugin, error) {
client, err := api.NewClient(nil)
if err != nil {
return nil, err
}
v := &vault{
store: store,
client: client,
}
for _, opt := range opts {
opt(v)
}
if v.auth == "kubernetes" {
err = v.initKubernetes()
if err != nil {
return nil, err
}
}
v.start() // start the refresh process.
return v, nil
}
func (v *vault) initKubernetes() error {
if v.renew == 0 {
return errors.New("vault: token renewal not configured")
}
token, ttl, err := getKubernetesToken(
v.kubeAuth.addr,
v.kubeAuth.role,
v.kubeAuth.mount,
"/var/run/secrets/kubernetes.io/serviceaccount/token",
)
if err != nil {
logrus.Debugf("vault: failed to obtain token via kubernetes-auth backend: %s", err)
return err
}
v.client.SetToken(token)
v.ttl = ttl
return nil
}
func (v *vault) SecretListBuild(repo *model.Repo, build *model.Build) ([]*model.Secret, error) {
return v.list(repo, build)
}
func (v *vault) list(repo *model.Repo, build *model.Build) ([]*model.Secret, error) {
conf, err := v.store.ConfigLoad(build.ConfigID)
if err != nil {
return nil, err
}
var (
in = []byte(conf.Data)
out = new(vaultConfig)
secrets []*model.Secret
)
err = yaml.Unmarshal(in, out)
if err != nil {
return nil, err
}
for key, val := range out.Secrets {
var path, field string
switch {
case val.Path != "":
path = val.Path
case val.File != "":
path = val.File
case val.Vault != "":
path = val.Vault
case val.DriverOpts.Path != "":
path = val.DriverOpts.Path
field = val.DriverOpts.Key
}
if field == "" {
field = "value"
}
if path == "" {
continue
}
logrus.Debugf("vault: read secret: %s", path)
vaultSecret, err := v.get(path, field)
if err != nil {
logrus.Debugf("vault: read secret failed: %s: %s", path, err)
return nil, err
}
if vaultSecret == nil {
logrus.Debugf("vault: read secret failed: %s: not found or empty value", path)
continue
}
if !vaultSecret.Match(repo.FullName) {
logrus.Debugf("vault: read secret: %s: restricted: %s", path, repo.FullName)
continue
}
logrus.Debugf("vault: read secret success: %s", err)
secrets = append(secrets, &model.Secret{
Name: key,
Value: vaultSecret.Value,
Events: vaultSecret.Event,
Images: vaultSecret.Image,
})
}
return secrets, nil
}
func (v *vault) get(path, key string) (*vaultSecret, error) {
secret, err := v.client.Logical().Read(path)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, nil
}
return parseVaultSecret(secret.Data, key), nil
}
// start starts the renewal loop.
func (v *vault) start() {
if v.renew == 0 || v.ttl == 0 {
logrus.Debugf("vault: token renewal disabled")
return
}
if v.done != nil {
close(v.done)
}
logrus.Infof("vault: token renewal enabled: renew every %v", v.renew)
v.done = make(chan struct{})
if v.renew != 0 {
go v.renewLoop()
}
}
// stop stops the renewal loop.
func (v *vault) stop() {
close(v.done)
}
func (v *vault) renewLoop() {
for {
select {
case <-time.After(v.renew):
incr := int(v.ttl / time.Second)
logrus.Debugf("vault: refreshing token: increment %v", v.ttl)
_, err := v.client.Auth().Token().RenewSelf(incr)
if err != nil {
logrus.Errorf("vault: refreshing token failed: %s", err)
} else {
logrus.Debugf("vault: refreshing token succeeded")
}
case <-v.done:
return
}
}
}
type vaultSecret struct {
Value string
Image []string
Event []string
Repo []string
}
func parseVaultSecret(data map[string]interface{}, key string) *vaultSecret {
secret := new(vaultSecret)
if vvalue, ok := data[key]; ok {
if svalue, ok := vvalue.(string); ok {
secret.Value = svalue
}
}
if vimage, ok := data["image"]; ok {
if simage, ok := vimage.(string); ok {
secret.Image = strings.Split(simage, ",")
}
}
if vevent, ok := data["event"]; ok {
if sevent, ok := vevent.(string); ok {
secret.Event = strings.Split(sevent, ",")
}
}
if vrepo, ok := data["repo"]; ok {
if srepo, ok := vrepo.(string); ok {
secret.Repo = strings.Split(srepo, ",")
}
}
if secret.Event == nil {
secret.Event = []string{}
}
if secret.Image == nil {
secret.Image = []string{}
}
if secret.Repo == nil {
secret.Repo = []string{}
}
return secret
}
func (v *vaultSecret) Match(name string) bool {
if len(v.Repo) == 0 {
return true
}
for _, pattern := range v.Repo {
if ok, _ := path.Match(pattern, name); ok {
return true
}
}
return false
}

View file

@ -1,108 +0,0 @@
// Copyright 2018 Drone.IO Inc
// Use of this software is governed by the Drone Enterpise License
// that can be found in the LICENSE file.
package vault
import (
"os"
"reflect"
"testing"
"github.com/hashicorp/vault/api"
"github.com/kr/pretty"
)
// Use the following snippet to spin up a local vault
// server for integration testing:
//
// docker run --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=dummy' -p 8200:8200 vault
// export VAULT_ADDR=http://127.0.0.1:8200
// export VAULT_TOKEN=dummy
func TestVaultGet(t *testing.T) {
if os.Getenv("VAULT_TOKEN") == "" {
t.SkipNow()
return
}
client, err := api.NewClient(nil)
if err != nil {
t.Error(err)
return
}
_, err = client.Logical().Write("secret/testing/drone/a", map[string]interface{}{
"value": "hello",
"fr": "bonjour",
"image": "golang",
"event": "push,pull_request",
"repo": "octocat/hello-world,github/*",
})
if err != nil {
t.Error(err)
return
}
plugin := vault{client: client}
secret, err := plugin.get("secret/testing/drone/a", "value")
if err != nil {
t.Error(err)
return
}
if got, want := secret.Value, "hello"; got != want {
t.Errorf("Expect secret value %s, got %s", want, got)
}
secret, err = plugin.get("secret/testing/drone/a", "fr")
if err != nil {
t.Error(err)
return
}
if got, want := secret.Value, "bonjour"; got != want {
t.Errorf("Expect secret value %s, got %s", want, got)
}
secret, err = plugin.get("secret/testing/drone/404", "value")
if err != nil {
t.Errorf("Expect silent failure when secret does not exist, got %s", err)
}
if secret != nil {
t.Errorf("Expect nil secret when path does not exist")
}
}
func TestVaultSecretParse(t *testing.T) {
data := map[string]interface{}{
"value": "password",
"event": "push,tag",
"image": "plugins/s3,plugins/ec2",
"repo": "octocat/hello-world,github/*",
}
want := vaultSecret{
Value: "password",
Event: []string{"push", "tag"},
Image: []string{"plugins/s3", "plugins/ec2"},
Repo: []string{"octocat/hello-world", "github/*"},
}
got := parseVaultSecret(data, "value")
if !reflect.DeepEqual(want, *got) {
t.Errorf("Failed read Secret.Data")
pretty.Fdiff(os.Stderr, want, got)
}
}
func TestVaultSecretMatch(t *testing.T) {
secret := vaultSecret{
Repo: []string{"octocat/hello-world", "github/*"},
}
if secret.Match("octocat/*") {
t.Errorf("Expect octocat/* does not match")
}
if !secret.Match("octocat/hello-world") {
t.Errorf("Expect octocat/hello-world does match")
}
if !secret.Match("github/hello-world") {
t.Errorf("Expect github/hello-world does match wildcard")
}
}