diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..abd17c1 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,688 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:25e90949d88e66bcbb646626a293c77a97237b37a8f854c1e8ae817b74b5c2cf" + name = "cloud.google.com/go" + packages = ["compute/metadata"] + pruneopts = "" + revision = "c9474f2f8deb81759839474b6bd1726bbfe1c1c4" + version = "v0.36.0" + +[[projects]] + digest = "1:e1b859e3d9e90007d5fbf25edf57733b224f1857f6592636130afab3af8cfae7" + name = "contrib.go.opencensus.io/exporter/ocagent" + packages = ["."] + pruneopts = "" + revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d" + version = "v0.2.0" + +[[projects]] + digest = "1:f24d900a7aeff07f60d783a3e1c394e494ab119ab66278c69da9848b40626734" + name = "github.com/Azure/go-autorest" + packages = [ + "autorest", + "autorest/adal", + "autorest/azure", + "autorest/date", + "logger", + "tracing", + ] + pruneopts = "" + revision = "f4369d4c79bf40df5e86def1e0f54c7ef261a51c" + version = "v11.5.0" + +[[projects]] + digest = "1:0b2d5839372f6dc106fcaa70b6bd5832789a633c4e470540f76c2ec6c560e1c1" + name = "github.com/census-instrumentation/opencensus-proto" + packages = [ + "gen-go/agent/common/v1", + "gen-go/agent/trace/v1", + "gen-go/resource/v1", + "gen-go/trace/v1", + ] + pruneopts = "" + revision = "7f2434bc10da710debe5c4315ed6d4df454b4024" + version = "v0.1.0" + +[[projects]] + digest = "1:0deddd908b6b4b768cfc272c16ee61e7088a60f7fe2f06c547bd3d8e1f8b8e77" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:6098222470fe0172157ce9bbef5d2200df4edde17ee649c5d6e48330e4afa4c6" + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + pruneopts = "" + revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" + version = "v3.2.0" + +[[projects]] + digest = "1:4216202f4088a73e2982df875e2f0d1401137bbc248e57391e70547af167a18a" + name = "github.com/evanphx/json-patch" + packages = ["."] + pruneopts = "" + revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5" + version = "v4.1.0" + +[[projects]] + digest = "1:fd53b471edb4c28c7d297f617f4da0d33402755f58d6301e7ca1197ef0a90937" + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys", + ] + pruneopts = "" + revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c" + version = "v1.2.1" + +[[projects]] + digest = "1:d3d38150b6d77b2aad42a9e105170538b6563518993d43df78a1add6e31cce62" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + "ptypes/wrappers", + ] + pruneopts = "" + revision = "c823c79ea1570fb5ff454033735a8e68575d1d0f" + version = "v1.3.0" + +[[projects]] + branch = "master" + digest = "1:1e5b1e14524ed08301977b7b8e10c719ed853cbf3f24ecb66fae783a46f207a6" + name = "github.com/google/btree" + packages = ["."] + pruneopts = "" + revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" + +[[projects]] + branch = "master" + digest = "1:754f77e9c839b24778a4b64422236d38515301d2baeb63113aa3edc42e6af692" + name = "github.com/google/gofuzz" + packages = ["."] + pruneopts = "" + revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" + +[[projects]] + digest = "1:16b2837c8b3cf045fa2cdc82af0cf78b19582701394484ae76b2c3bc3c99ad73" + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions", + ] + pruneopts = "" + revision = "7c663266750e7d82587642f65e60bc4083f1f84e" + version = "v0.2.0" + +[[projects]] + branch = "master" + digest = "1:bf7cdda23aa9d3b032fb4c25177ebe85f5f910697a2aed1b943de1aaa7ef9827" + name = "github.com/gophercloud/gophercloud" + packages = [ + ".", + "openstack", + "openstack/identity/v2/tenants", + "openstack/identity/v2/tokens", + "openstack/identity/v3/tokens", + "openstack/utils", + "pagination", + ] + pruneopts = "" + revision = "8788235096d743c9abd213ba53adca6b0e9d0b58" + +[[projects]] + branch = "master" + digest = "1:326d7083af3723768cd8150db99b8ac730837b05ef290d5a042562905cc26210" + name = "github.com/gregjones/httpcache" + packages = [ + ".", + "diskcache", + ] + pruneopts = "" + revision = "3befbb6ad0cc97d4c25d851e9528915809e1a22f" + +[[projects]] + digest = "1:31bfd110d31505e9ffbc9478e31773bf05bf02adcaeb9b139af42684f9294c13" + name = "github.com/imdario/mergo" + packages = ["."] + pruneopts = "" + revision = "7c29201646fa3de8506f701213473dd407f19646" + version = "v0.3.7" + +[[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + pruneopts = "" + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + digest = "1:b79fc583e4dc7055ed86742e22164ac41bf8c0940722dbcb600f1a3ace1a8cb5" + name = "github.com/json-iterator/go" + packages = ["."] + pruneopts = "" + revision = "1624edc4454b8682399def8740d46db5e4362ba4" + version = "v1.1.5" + +[[projects]] + digest = "1:0c0ff2a89c1bb0d01887e1dac043ad7efbf3ec77482ef058ac423d13497e16fd" + name = "github.com/modern-go/concurrent" + packages = ["."] + pruneopts = "" + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" + name = "github.com/modern-go/reflect2" + packages = ["."] + pruneopts = "" + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[[projects]] + branch = "master" + digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc" + name = "github.com/petar/GoLLRB" + packages = ["llrb"] + pruneopts = "" + revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" + +[[projects]] + digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f" + name = "github.com/peterbourgon/diskv" + packages = ["."] + pruneopts = "" + revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" + version = "v2.0.1" + +[[projects]] + digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6" + name = "github.com/spf13/cobra" + packages = ["."] + pruneopts = "" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" + +[[projects]] + digest = "1:cbaf13cdbfef0e4734ed8a7504f57fe893d471d62a35b982bf6fb3f036449a66" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "" + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + +[[projects]] + digest = "1:381bcbeb112a51493d9d998bbba207a529c73dbb49b3fd789e48c63fac1f192c" + name = "github.com/stretchr/testify" + packages = ["assert"] + pruneopts = "" + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[[projects]] + digest = "1:ad67dfd3799a2c58f6c65871dd141d8b53f61f600aec48ce8d7fa16a4d5476f8" + name = "go.opencensus.io" + packages = [ + ".", + "exemplar", + "internal", + "internal/tagencoding", + "plugin/ochttp", + "plugin/ochttp/propagation/b3", + "plugin/ochttp/propagation/tracecontext", + "stats", + "stats/internal", + "stats/view", + "tag", + "trace", + "trace/internal", + "trace/propagation", + "trace/tracestate", + ] + pruneopts = "" + revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b" + version = "v0.18.0" + +[[projects]] + branch = "master" + digest = "1:7a77b79efe106f3304dcf50dc86836151758f246169b527722552a5eb2ae14fc" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "" + revision = "8dd112bcdc25174059e45e07517d9fc663123347" + +[[projects]] + branch = "master" + digest = "1:2b08539d056d6b2da4233648f5014d84cb70a9c278523374c75776a75a32d03e" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "trace", + ] + pruneopts = "" + revision = "92fc7df08ae7536330f5a21328292abfa70520a8" + +[[projects]] + branch = "master" + digest = "1:ffae4a89b63a2c845533a393b3340f8696898b11b71da1b187f82f08135c23a0" + name = "golang.org/x/oauth2" + packages = [ + ".", + "google", + "internal", + "jws", + "jwt", + ] + pruneopts = "" + revision = "e64efc72b421e893cbf63f17ba2221e7d6d0b0f3" + +[[projects]] + branch = "master" + digest = "1:0142c968b74c157abbb0220c05fa2bdde8a3a4509d6134b35ef75d5b58afb721" + name = "golang.org/x/sync" + packages = ["semaphore"] + pruneopts = "" + revision = "e225da77a7e68af35c70ccbf71af2b83e6acac3c" + +[[projects]] + branch = "master" + digest = "1:74ce8329385730bb2d01e4e91b66183beceeb1512084e4253653ac2439f1ef8c" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "" + revision = "a34e9553db1e492c9a76e60db2296ae7e5fbb772" + +[[projects]] + digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + digest = "1:14cb1d4240bcbbf1386ae763957e04e2765ec4e4ce7bb2769d05fa6faccd774e" + name = "golang.org/x/time" + packages = ["rate"] + pruneopts = "" + revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd" + +[[projects]] + digest = "1:1ef3746d0b0a2ab4147e9fe251202756ff89d181c3c3cc67abdf40e375243cbc" + name = "google.golang.org/api" + packages = [ + "cloudresourcemanager/v1", + "gensupport", + "googleapi", + "googleapi/internal/uritemplates", + "support/bundler", + ] + pruneopts = "" + revision = "19e022d8cf43ce81f046bae8cc18c5397cc7732f" + version = "v0.1.0" + +[[projects]] + digest = "1:bc09e719c4e2a15d17163f5272d9a3131c45d77542b7fdc53ff518815bc19ab3" + name = "google.golang.org/appengine" + packages = [ + ".", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/urlfetch", + "urlfetch", + ] + pruneopts = "" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" + +[[projects]] + branch = "master" + digest = "1:bedc60c52eb064eca6d7ce3321602522c5f50b6635aa7bc93c5624f1e65f9eda" + name = "google.golang.org/genproto" + packages = ["googleapis/rpc/status"] + pruneopts = "" + revision = "4f5b463f9597cbe0dd13a6a2cd4f85e788d27508" + +[[projects]] + digest = "1:b6c17b0c657f047118ae59b358950b28515914512cf3de02388cc42e33a92520" + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "binarylog/grpc_binarylog_v1", + "codes", + "connectivity", + "credentials", + "credentials/internal", + "encoding", + "encoding/proto", + "grpclog", + "internal", + "internal/backoff", + "internal/binarylog", + "internal/channelz", + "internal/envconfig", + "internal/grpcrand", + "internal/grpcsync", + "internal/syscall", + "internal/transport", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + ] + pruneopts = "" + revision = "2fdaae294f38ed9a121193c51ec99fecd3b13eb7" + version = "v1.19.0" + +[[projects]] + digest = "1:75fb3fcfc73a8c723efde7777b40e8e8ff9babf30d8c56160d01beffea8a95a6" + name = "gopkg.in/inf.v0" + packages = ["."] + pruneopts = "" + revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" + version = "v0.9.1" + +[[projects]] + digest = "1:cedccf16b71e86db87a24f8d4c70b0a855872eb967cb906a66b95de56aefbd0d" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" + +[[projects]] + digest = "1:8a3902b1f1aab51953de9741e4a62daaab441788d85ba7f50709ceca8e26b6ff" + name = "k8s.io/api" + packages = [ + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "auditregistration/v1alpha1", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "autoscaling/v2beta2", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "coordination/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "scheduling/v1beta1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1", + ] + pruneopts = "" + revision = "5cb15d34447165a97c76ed5a60e4e99c8a01ecfe" + version = "kubernetes-1.13.4" + +[[projects]] + digest = "1:c05610391a133b223e1736a3b8cbd725da30f64c0c6a93d6422714ccfd8f4a73" + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1beta1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/clock", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/mergepatch", + "pkg/util/naming", + "pkg/util/net", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/strategicpatch", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/json", + "third_party/forked/golang/reflect", + ] + pruneopts = "" + revision = "86fb29eff6288413d76bd8506874fddd9fccdff0" + version = "kubernetes-1.13.4" + +[[projects]] + digest = "1:96ab89894f66b77a0137bba12e607c6a9be992acadfb075b5602939e8519a157" + name = "k8s.io/client-go" + packages = [ + "discovery", + "discovery/fake", + "kubernetes", + "kubernetes/fake", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1alpha1/fake", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/admissionregistration/v1beta1/fake", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1/fake", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta1/fake", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/apps/v1beta2/fake", + "kubernetes/typed/auditregistration/v1alpha1", + "kubernetes/typed/auditregistration/v1alpha1/fake", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1/fake", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authentication/v1beta1/fake", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1/fake", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/authorization/v1beta1/fake", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v1/fake", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/autoscaling/v2beta1/fake", + "kubernetes/typed/autoscaling/v2beta2", + "kubernetes/typed/autoscaling/v2beta2/fake", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1/fake", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v1beta1/fake", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/batch/v2alpha1/fake", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/certificates/v1beta1/fake", + "kubernetes/typed/coordination/v1beta1", + "kubernetes/typed/coordination/v1beta1/fake", + "kubernetes/typed/core/v1", + "kubernetes/typed/core/v1/fake", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/events/v1beta1/fake", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/extensions/v1beta1/fake", + "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1/fake", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/policy/v1beta1/fake", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1/fake", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1alpha1/fake", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/rbac/v1beta1/fake", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1alpha1/fake", + "kubernetes/typed/scheduling/v1beta1", + "kubernetes/typed/scheduling/v1beta1/fake", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/settings/v1alpha1/fake", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1/fake", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1alpha1/fake", + "kubernetes/typed/storage/v1beta1", + "kubernetes/typed/storage/v1beta1/fake", + "pkg/apis/clientauthentication", + "pkg/apis/clientauthentication/v1alpha1", + "pkg/apis/clientauthentication/v1beta1", + "pkg/version", + "plugin/pkg/client/auth", + "plugin/pkg/client/auth/azure", + "plugin/pkg/client/auth/exec", + "plugin/pkg/client/auth/gcp", + "plugin/pkg/client/auth/oidc", + "plugin/pkg/client/auth/openstack", + "rest", + "rest/watch", + "testing", + "third_party/forked/golang/template", + "tools/auth", + "tools/clientcmd", + "tools/clientcmd/api", + "tools/clientcmd/api/latest", + "tools/clientcmd/api/v1", + "tools/metrics", + "tools/reference", + "transport", + "util/cert", + "util/connrotation", + "util/flowcontrol", + "util/homedir", + "util/integer", + "util/jsonpath", + ] + pruneopts = "" + revision = "e64494209f554a6723674bd494d69445fb76a1d4" + version = "v10.0.0" + +[[projects]] + digest = "1:5afb58506f8972419a6e93f051513854291127189f04607aac1388eb378c0608" + name = "k8s.io/klog" + packages = ["."] + pruneopts = "" + revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0" + version = "v0.2.0" + +[[projects]] + branch = "master" + digest = "1:59cce16b16002977ebfa3cbc6a72922d04704d3d4b9ee85ec916057d6b52762e" + name = "k8s.io/kube-openapi" + packages = ["pkg/util/proto"] + pruneopts = "" + revision = "b3a7cee44a305be0a69e1b9ac03018307287e1b0" + +[[projects]] + digest = "1:321081b4a44256715f2b68411d8eda9a17f17ebfe6f0cc61d2cc52d11c08acfa" + name = "sigs.k8s.io/yaml" + packages = ["."] + pruneopts = "" + revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480" + version = "v1.1.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/spf13/cobra", + "github.com/stretchr/testify/assert", + "golang.org/x/net/context", + "golang.org/x/oauth2/google", + "google.golang.org/api/cloudresourcemanager/v1", + "k8s.io/api/rbac/v1", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/fake", + "k8s.io/client-go/plugin/pkg/client/auth", + "k8s.io/client-go/plugin/pkg/client/auth/gcp", + "k8s.io/client-go/rest", + "k8s.io/client-go/tools/clientcmd", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..4e5d13a --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,12 @@ +[[constraint]] + name = "github.com/spf13/cobra" + version = "~0.0.3" +[[constraint]] + name = "k8s.io/api" + version = "kubernetes-1.13.4" +[[constraint]] + name = "k8s.io/apimachinery" + version = "kubernetes-1.13.4" +[[constraint]] + name = "k8s.io/client-go" + version = "~10.0.0" diff --git a/README.md b/README.md index 2b53ab1..19f6eeb 100644 --- a/README.md +++ b/README.md @@ -27,19 +27,10 @@ rob@example.com cluster-wide ClusterRole/view rob@example.com nginx-ingress ClusterRole/edit ``` -The wide output option includes the kind of subject (user, service account, or group), along with the source role binding. +The wide output option includes the kind of subject along with the source role binding. ``` -rbac-lookup rob -owide - -SUBJECT SCOPE ROLE SOURCE -User/rob@example.com cluster-wide ClusterRole/view ClusterRoleBinding/rob-cluster-view -User/rob@example.com nginx-ingress ClusterRole/edit RoleBinding/rob-edit -``` - -With a more generic query, we can see that a variety of users and service accounts can be returned, as long as they match the query. -``` -rbac-lookup ro -owide +rbac-lookup ro --output wide SUBJECT SCOPE ROLE SOURCE User/rob@example.com cluster-wide ClusterRole/view ClusterRoleBinding/rob-cluster-view @@ -48,12 +39,15 @@ User/ron@example.com web ClusterRole/edit RoleBinding/ron- ServiceAccount/rops infra ClusterRole/admin RoleBinding/rops-admin ``` -Of course a query is an optional parameter for rbac-lookup. You could simply run `rbac-lookup` to get a full picture of authorization in your cluster, and then pipe that output to something like grep for your own more advanced filtering. +It's also possible to filter output by the kind of RBAC Subject. The `--kind` or `-k` parameter accepts `user`, `group`, and `serviceaccount` as values. + ``` -rbac-lookup | grep rob +rbac-lookup ro --output wide --kind user +SUBJECT SCOPE ROLE SOURCE User/rob@example.com cluster-wide ClusterRole/view ClusterRoleBinding/rob-cluster-view User/rob@example.com nginx-ingress ClusterRole/edit RoleBinding/rob-edit +User/ron@example.com web ClusterRole/edit RoleBinding/ron-edit ``` ### GKE IAM Integration @@ -73,7 +67,7 @@ rob@example.com project-wide IAM/viewer Of course this GKE integration also supports wide output, in this case referencing the specific IAM roles that are assigned to a user. ``` -rbac-lookup rob --gke -owide +rbac-lookup rob --gke --output wide SUBJECT SCOPE ROLE SOURCE User/rob@example.com cluster-wide ClusterRole/view ClusterRoleBinding/rob-cluster-view @@ -84,8 +78,14 @@ User/rob@example.com project-wide IAM/gcp-viewer IAMRole/viewer At this point this integration only supports standard IAM roles, and is not advanced enough to include any custom roles. For a full list of supported roles and how they are mapped, view [lookup/gke_roles.go](lookup/gke_roles.go). -### Kubernetes Configuration -If a `KUBECONFIG` environment variable is specified, rbac-lookup will attempt to use the config at that path, otherwise it will default to `~/.kube/config`. +## Flags Supported +``` + --context string context to use for Kubernetes config + --gke enable GKE integration + -h, --help help for rbac-lookup + -k, --kind string filter by this RBAC subject kind (user, group, serviceaccount) + -o, --output string output format (normal, wide) +``` ## RBAC Manager While RBAC Lookup helps provide visibility into Kubernetes auth, RBAC Manager helps make auth simpler to manage. This is a Kubernetes operator that enables more concise RBAC configuration that is easier to scale and automate. For more information, see [RBAC Manager on GitHub](https://github.com/reactiveops/rbac-manager). diff --git a/cmd/root.go b/cmd/root.go index 1ba5f74..fa6ae9c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,13 +17,16 @@ package cmd import ( "fmt" "os" + "strings" "github.com/reactiveops/rbac-lookup/lookup" "github.com/spf13/cobra" ) -var output string -var gke bool +var outputFormat string +var enableGke bool +var kubeContext string +var subjectKind string var rootCmd = &cobra.Command{ Use: "rbac-lookup [subject query]", @@ -32,16 +35,20 @@ var rootCmd = &cobra.Command{ Args: cobra.RangeArgs(0, 1), Run: func(cmd *cobra.Command, args []string) { if err := cmd.ParseFlags(args); err != nil { - fmt.Printf("Error parsing flags: %v", err) + fmt.Printf("Error parsing flags: %v\n", err) } - lookup.List(args, output, gke) + subjectKind = strings.ToLower(subjectKind) + + lookup.List(args, kubeContext, outputFormat, subjectKind, enableGke) }, } func init() { - rootCmd.PersistentFlags().StringVarP(&output, "output", "o", "", "output format (normal,wide)") - rootCmd.PersistentFlags().BoolVar(&gke, "gke", false, "enable GKE integration") + rootCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "", "output format (normal, wide)") + rootCmd.PersistentFlags().StringVarP(&kubeContext, "context", "", "", "context to use for Kubernetes config") + rootCmd.PersistentFlags().StringVarP(&subjectKind, "kind", "k", "", "filter by this RBAC subject kind (user, group, serviceaccount)") + rootCmd.PersistentFlags().BoolVar(&enableGke, "gke", false, "enable GKE integration") } // Execute is the primary entrypoint for this CLI diff --git a/cmd/version.go b/cmd/version.go index d24de8b..f565efd 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -28,6 +28,6 @@ var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of rbac-lookup", Run: func(cmd *cobra.Command, args []string) { - fmt.Println("rbac-lookup version 0.2.1") + fmt.Println("rbac-lookup version 0.3.0") }, } diff --git a/go.mod b/go.mod deleted file mode 100644 index 114c547..0000000 --- a/go.mod +++ /dev/null @@ -1,40 +0,0 @@ -module github.com/reactiveops/rbac-lookup - -require ( - cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 // indirect - github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e // indirect - github.com/golang/glog v0.0.0-20141105023935-44145f04b68c // indirect - github.com/google/btree v0.0.0-20160524151835-7d79101e329e // indirect - github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 // indirect - github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d // indirect - github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 // indirect - github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be // indirect - github.com/kr/pretty v0.1.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect - github.com/onsi/ginkgo v1.7.0 // indirect - github.com/onsi/gomega v1.4.3 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/cobra v0.0.3 - github.com/spf13/pflag v1.0.1 // indirect - github.com/stretchr/testify v1.2.2 - golang.org/x/crypto v0.0.0-20180222182404-49796115aa4b // indirect - golang.org/x/net v0.0.0-20180906233101-161cd47e91fd - golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181 - golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect - golang.org/x/time v0.0.0-20161028155119-f51c12702a4d // indirect - google.golang.org/api v0.0.0-20180925145026-e5ba110cb6cd - google.golang.org/appengine v0.0.0-20180731164958-4216e58b9158 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/inf.v0 v0.9.0 // indirect - gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect - k8s.io/api v0.0.0-20181130031204-d04500c8c3dd - k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d - k8s.io/client-go v8.0.0+incompatible - k8s.io/kube-openapi v0.0.0-20180620173706-91cfa479c814 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index e629ade..0000000 --- a/go.sum +++ /dev/null @@ -1,97 +0,0 @@ -cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2 h1:BD5IDvMK5RQqnDi7Fbizwoad9Uus/Hs/xJ1zMYVXlS8= -cloud.google.com/go v0.0.0-20160913182117-3b1ae45394a2/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e h1:ago6fNuQ6IhszPsXkeU7qRCyfsIX7L67WDybsAPkLl8= -github.com/gogo/protobuf v0.0.0-20170330071051-c0656edd0d9e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20141105023935-44145f04b68c h1:CbdkBQ1/PiAo0FYJhQGwASD8wrgNvTdf01g6+O9tNuA= -github.com/golang/glog v0.0.0-20141105023935-44145f04b68c/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v0.0.0-20160524151835-7d79101e329e h1:JHB7F/4TJCrYBW8+GZO8VkWDj1jxcWuCl6uxKODiyi4= -github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367 h1:ScAXWS+TR6MZKex+7Z8rneuSJH+FSDqd6ocQyl+ZHo4= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 h1:6TSoaYExHper8PYsJu23GWVNOyYRCSnIFyxKgLSZ54w= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1 h1:FeeCi0I2Fu8kA8IXrdVPtGzym+mW9bzfj9f26EaES9k= -github.com/imdario/mergo v0.0.0-20141206190957-6633656539c1/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -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= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/crypto v0.0.0-20180222182404-49796115aa4b h1:/GxqO8gbyb+sNnviFY2IIMrtm8vGg6NEJDft68wJY/g= -golang.org/x/crypto v0.0.0-20180222182404-49796115aa4b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181 h1:/4OaQ4bC66Oq9JDhUnxTjBGt8XBhDuwgMRXHgvfcCUY= -golang.org/x/oauth2 v0.0.0-20170412232759-a6bd8cefa181/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g= -golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -google.golang.org/api v0.0.0-20180925145026-e5ba110cb6cd h1:45hBKqFLSVPWQwYat5l0VtlKhPZ0naI85v984m1kXTU= -google.golang.org/api v0.0.0-20180925145026-e5ba110cb6cd/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/appengine v0.0.0-20180731164958-4216e58b9158 h1:jmER6o8Dn+YkWq9eCP6ZP64Kxq2y2VXkWx/3QaSE+rU= -google.golang.org/appengine v0.0.0-20180731164958-4216e58b9158/go.mod h1:becAO19CitOrUq7nfYuyxycOBJNZgjTqYPI+mvwLjCs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/api v0.0.0-20181130031204-d04500c8c3dd h1:5aHsneN62ehs/tdtS9tWZlhVk68V7yms/Qw7nsGmvCA= -k8s.io/api v0.0.0-20181130031204-d04500c8c3dd/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d h1:MZjlsu9igBoVPZkXpIGoxI6EonqNsXXZU7hhvfQLkd4= -k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/client-go v8.0.0+incompatible h1:tTI4hRmb1DRMl4fG6Vclfdi6nTM82oIrTT7HfitmxC4= -k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/kube-openapi v0.0.0-20180620173706-91cfa479c814 h1:WsxVnILg9qqVsw/7wiJvimCxl8y/OUwIYyvzbZw/FxY= -k8s.io/kube-openapi v0.0.0-20180620173706-91cfa479c814/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= diff --git a/lookup/list.go b/lookup/list.go index 2ebc7ef..819f43a 100644 --- a/lookup/list.go +++ b/lookup/list.go @@ -15,19 +15,16 @@ package lookup import ( - "flag" "fmt" "os" - "path/filepath" "strings" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - // Required for GKE Auth - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - // Required for dex / oidc - _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" + // Required for GKE, OIDC, and more + _ "k8s.io/client-go/plugin/pkg/client/auth" ) type clusterInfo struct { @@ -37,11 +34,19 @@ type clusterInfo struct { } // List outputs rbac bindings where subject names match given string -func List(args []string, outputFormat string, enableGke bool) { - kubeconfig := getKubeConfig() - clientset, err := getClientSet(kubeconfig) +func List(args []string, kubeContext, outputFormat, subjectKind string, enableGke bool) { + clientConfig := getClientConfig(kubeContext) + + kubeconfig, err := clientConfig.ClientConfig() + if err != nil { + fmt.Printf("Error getting Kubernetes config: %v\n", err) + os.Exit(1) + } + + clientset, err := kubernetes.NewForConfig(kubeconfig) if err != nil { - panic(err.Error()) + fmt.Printf("Error generating Kubernetes clientset from kubeconfig: %v\n", err) + os.Exit(2) } filter := "" @@ -51,53 +56,50 @@ func List(args []string, outputFormat string, enableGke bool) { l := lister{ filter: filter, + subjectKind: subjectKind, clientset: clientset, rbacSubjectsByScope: make(map[string]rbacSubject), } if enableGke { - ci := getClusterInfo(kubeconfig) - l.gkeProjectName = ci.GkeProjectName + rawConfig, err := clientConfig.RawConfig() + if err != nil { + fmt.Printf("Error getting Kubernetes raw config: %v\n", err) + os.Exit(3) + } + + ci := getClusterInfo(&rawConfig, kubeContext) + if ci.GkeProjectName == "" { + fmt.Printf("Error parsing GKE project name from kubeconfig\n") + } else { + l.gkeProjectName = ci.GkeProjectName + } } loadErr := l.loadAll() if loadErr != nil { - fmt.Printf("Error loading RBAC: %v\n", loadErr) - os.Exit(1) + fmt.Printf("Error loading RBAC Bindings: %v\n", loadErr) + os.Exit(4) } l.printRbacBindings(outputFormat) } -func getKubeConfig() string { - var kubeconfig string - if os.Getenv("KUBECONFIG") != "" { - kubeconfig = os.Getenv("KUBECONFIG") - } else if home := homeDir(); home != "" { - kubeconfig = filepath.Join(home, ".kube", "config") - } else { - fmt.Println("Parsing kubeconfig failed, please set KUBECONFIG env var") - os.Exit(1) - } - - if _, err := os.Stat(kubeconfig); err != nil { - // kubeconfig doesn't exist - fmt.Printf("%s does not exist - please make sure you have a kubeconfig configured.\n", kubeconfig) - panic(err.Error()) - } - - return kubeconfig +func getClientConfig(kubeContext string) clientcmd.ClientConfig { + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + clientcmd.NewDefaultClientConfigLoadingRules(), + &clientcmd.ConfigOverrides{CurrentContext: kubeContext}, + ) } -func getClusterInfo(kubeconfig string) *clusterInfo { - c, err := clientcmd.LoadFromFile(kubeconfig) - if err != nil { - panic(err.Error()) +func getClusterInfo(c *clientcmdapi.Config, kubeContext string) *clusterInfo { + context := c.Contexts[c.CurrentContext] + if kubeContext != "" { + context = c.Contexts[kubeContext] } - currentContext := c.Contexts[c.CurrentContext] - if currentContext.Cluster != "" { - s := strings.Split(currentContext.Cluster, "_") + if context.Cluster != "" { + s := strings.Split(context.Cluster, "_") if s[0] == "gke" { return &clusterInfo{ ClusterName: s[3], @@ -106,24 +108,6 @@ func getClusterInfo(kubeconfig string) *clusterInfo { } } } - return &clusterInfo{} -} - -func getClientSet(kubeconfig string) (*kubernetes.Clientset, error) { - flag.Parse() - // use the current context in kubeconfig - config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) - if err != nil { - return nil, err - } - - // create the clientset - return kubernetes.NewForConfig(config) -} -func homeDir() string { - if h := os.Getenv("HOME"); h != "" { - return h - } - return os.Getenv("USERPROFILE") // windows + return &clusterInfo{} } diff --git a/lookup/lister.go b/lookup/lister.go index 00261ed..1de9c6b 100644 --- a/lookup/lister.go +++ b/lookup/lister.go @@ -37,6 +37,7 @@ type lister struct { clientset kubernetes.Interface filter string gkeProjectName string + subjectKind string rbacSubjectsByScope map[string]rbacSubject } @@ -109,7 +110,7 @@ func (l *lister) loadRoleBindings() error { for _, roleBinding := range roleBindings.Items { for _, subject := range roleBinding.Subjects { - if l.filter == "" || strings.Contains(subject.Name, l.filter) { + if l.nameMatches(subject.Name) && l.kindMatches(subject.Kind) { if rbacSubj, exist := l.rbacSubjectsByScope[subject.Name]; exist { rbacSubj.addRoleBinding(&roleBinding) } else { @@ -136,7 +137,7 @@ func (l *lister) loadClusterRoleBindings() error { for _, clusterRoleBinding := range clusterRoleBindings.Items { for _, subject := range clusterRoleBinding.Subjects { - if l.filter == "" || strings.Contains(subject.Name, l.filter) { + if l.nameMatches(subject.Name) && l.kindMatches(subject.Kind) { if rbacSubj, exist := l.rbacSubjectsByScope[subject.Name]; exist { rbacSubj.addClusterRoleBinding(&clusterRoleBinding) } else { @@ -161,7 +162,7 @@ func (l *lister) loadGkeIamPolicy(policy *cloudresourcemanager.Policy) { s := strings.Split(member, ":") memberKind := strings.Title(s[0]) memberName := s[1] - if l.filter == "" || strings.Contains(memberName, l.filter) { + if l.nameMatches(memberName) && l.kindMatches(memberKind) { rbacSubj, exist := l.rbacSubjectsByScope[memberName] if !exist { rbacSubj = rbacSubject{ @@ -203,3 +204,17 @@ func (l *lister) loadGkeRoleBindings() error { return nil } + +func (l *lister) nameMatches(name string) bool { + return l.filter == "" || strings.Contains(name, l.filter) +} + +func (l *lister) kindMatches(kind string) bool { + if l.subjectKind == "" { + return true + } + + lowerKind := strings.ToLower(kind) + + return lowerKind == l.subjectKind +} diff --git a/lookup/lister_test.go b/lookup/lister_test.go index d7c8dae..94be22b 100644 --- a/lookup/lister_test.go +++ b/lookup/lister_test.go @@ -153,7 +153,7 @@ func TestLoadGke(t *testing.T) { l.loadGkeIamPolicy(policy) - assert.Len(t, l.rbacSubjectsByScope, 4, "Expected 2 rbac subjects") + assert.Len(t, l.rbacSubjectsByScope, 4, "Expected 4 rbac subjects") assert.EqualValues(t, l.rbacSubjectsByScope["jane@example.com"], rbacSubject{ Kind: "User", @@ -219,6 +219,69 @@ func TestLoadGke(t *testing.T) { }) } +func TestLoadGkeFilters(t *testing.T) { + policy := &cloudresourcemanager.Policy{ + Bindings: []*cloudresourcemanager.Binding{{ + Role: "roles/container.admin", + Members: []string{"user:jane@example.com", "user:joe@example.com"}, + }, { + Role: "roles/container.developer", + Members: []string{"serviceAccount:ci@example.iam.gserviceaccount.com"}, + }, { + Role: "roles/viewer", + Members: []string{"group:devs@example.com"}, + }, { + Role: "roles/owner", + Members: []string{"user:jane@example.com"}, + }}, + } + + l := genLister() + l.filter = "example" + l.subjectKind = "user" + + assert.Len(t, l.rbacSubjectsByScope, 0, "Expected no rbac subjects initially") + + l.loadGkeIamPolicy(policy) + + assert.Len(t, l.rbacSubjectsByScope, 2, "Expected 2 rbac subjects") + + assert.EqualValues(t, l.rbacSubjectsByScope["jane@example.com"], rbacSubject{ + Kind: "User", + RolesByScope: map[string][]simpleRole{ + "project-wide": {{ + Kind: "IAM", + Name: "gke-admin", + Source: simpleRoleSource{ + Kind: "IAMRole", + Name: "container.admin", + }, + }, { + Kind: "IAM", + Name: "gcp-owner", + Source: simpleRoleSource{ + Kind: "IAMRole", + Name: "owner", + }, + }}, + }, + }) + + assert.EqualValues(t, l.rbacSubjectsByScope["joe@example.com"], rbacSubject{ + Kind: "User", + RolesByScope: map[string][]simpleRole{ + "project-wide": {{ + Kind: "IAM", + Name: "gke-admin", + Source: simpleRoleSource{ + Kind: "IAMRole", + Name: "container.admin", + }, + }}, + }, + }) +} + func genLister() lister { return lister{ clientset: testclient.NewSimpleClientset(),