Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GCS: Use ACLs for GCE permissions #3726

Merged
merged 2 commits into from
Oct 30, 2017
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
2 changes: 1 addition & 1 deletion cmd/kops/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
return err
}

err = registry.WriteConfigDeprecated(configBase.Join(registry.PathClusterCompleted), fullCluster)
err = registry.WriteConfigDeprecated(cluster, configBase.Join(registry.PathClusterCompleted), fullCluster)
if err != nil {
return fmt.Errorf("error writing completed cluster spec: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/kops/edit_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func RunEditCluster(f *util.Factory, cmd *cobra.Command, args []string, out io.W
return preservedFile(err, file, out)
}

err = registry.WriteConfigDeprecated(configBase.Join(registry.PathClusterCompleted), fullCluster)
err = registry.WriteConfigDeprecated(newCluster, configBase.Join(registry.PathClusterCompleted), fullCluster)
if err != nil {
return preservedFile(fmt.Errorf("error writing completed cluster spec: %v", err), file, out)
}
Expand Down
1 change: 1 addition & 0 deletions cmd/kops/util/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go_library(
srcs = ["factory.go"],
visibility = ["//visibility:public"],
deps = [
"//pkg/acls/gce:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/simple:go_default_library",
"//pkg/client/simple/api:go_default_library",
Expand Down
15 changes: 9 additions & 6 deletions cmd/kops/util/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@ package util

import (
"fmt"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/util/pkg/vfs"
"net/url"
"strings"

"github.com/golang/glog"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/client-go/rest"
gceacls "k8s.io/kops/pkg/acls/gce"
kopsclient "k8s.io/kops/pkg/client/clientset_generated/clientset"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/client/simple/api"
"net/url"
"strings"
"k8s.io/kops/pkg/client/simple/vfsclientset"
"k8s.io/kops/util/pkg/vfs"
)

type FactoryOptions struct {
Expand All @@ -41,6 +42,8 @@ type Factory struct {
}

func NewFactory(options *FactoryOptions) *Factory {
gceacls.Register()

return &Factory{
options: options,
}
Expand Down
2 changes: 1 addition & 1 deletion federation/apply_federation.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (o *ApplyFederationOperation) federationContextForCluster(cluster *kopsapi.
federationKeystore := k8sapi.NewKubernetesKeystore(target.KubernetesClient, o.namespace)

checkExisting := true
context, err := fi.NewContext(target, nil, federationKeystore, nil, nil, checkExisting, nil)
context, err := fi.NewContext(target, nil, nil, federationKeystore, nil, nil, checkExisting, nil)
if err != nil {
return nil, err
}
Expand Down
2 changes: 2 additions & 0 deletions hack/.packages
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ k8s.io/kops/nodeup/pkg/bootstrap
k8s.io/kops/nodeup/pkg/distros
k8s.io/kops/nodeup/pkg/model
k8s.io/kops/nodeup/pkg/model/resources
k8s.io/kops/pkg/acls
k8s.io/kops/pkg/acls/gce
k8s.io/kops/pkg/apis/kops
k8s.io/kops/pkg/apis/kops/install
k8s.io/kops/pkg/apis/kops/model
Expand Down
2 changes: 1 addition & 1 deletion nodeup/pkg/bootstrap/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (i *Installation) Run() error {
}

checkExisting := true
context, err := fi.NewContext(target, cloud, keyStore, secretStore, configBase, checkExisting, tasks)
context, err := fi.NewContext(target, nil, cloud, keyStore, secretStore, configBase, checkExisting, tasks)
if err != nil {
return fmt.Errorf("error building context: %v", err)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/acls/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = [
"interface.go",
"plugins.go",
],
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/kops:go_default_library",
"//util/pkg/vfs:go_default_library",
],
)
15 changes: 15 additions & 0 deletions pkg/acls/gce/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["storage.go"],
visibility = ["//visibility:public"],
deps = [
"//pkg/acls:go_default_library",
"//pkg/apis/kops:go_default_library",
"//upup/pkg/fi/cloudup:go_default_library",
"//upup/pkg/fi/cloudup/gce:go_default_library",
"//util/pkg/vfs:go_default_library",
"//vendor/google.golang.org/api/storage/v1:go_default_library",
],
)
84 changes: 84 additions & 0 deletions pkg/acls/gce/storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package gce

import (
"fmt"

storage "google.golang.org/api/storage/v1"
"k8s.io/kops/pkg/acls"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/upup/pkg/fi/cloudup/gce"
"k8s.io/kops/util/pkg/vfs"
)

// gcsAclStrategy is the AclStrategy for objects written to google cloud storage
type gcsAclStrategy struct {
}

var _ acls.ACLStrategy = &gcsAclStrategy{}

// GetACL returns the ACL to use if this is a google cloud storage path
func (s *gcsAclStrategy) GetACL(p vfs.Path, cluster *kops.Cluster) (vfs.ACL, error) {
if kops.CloudProviderID(cluster.Spec.CloudProvider) != kops.CloudProviderGCE {
return nil, nil
}
gcsPath, ok := p.(*vfs.GSPath)
if !ok {
return nil, nil
}

bucketName := gcsPath.Bucket()
client := gcsPath.Client()

// TODO: Cache?
bucket, err := client.Buckets.Get(bucketName).Do()
if err != nil {
return nil, fmt.Errorf("error querying bucket %q: %v", bucketName, err)
}

// TODO: Cache?
cloud, err := cloudup.BuildCloud(cluster)
if err != nil {
return nil, err
}

serviceAccount, err := cloud.(gce.GCECloud).ServiceAccount()
if err != nil {
return nil, err
}

var acls []*storage.ObjectAccessControl
for _, a := range bucket.DefaultObjectAcl {
acls = append(acls, a)
}

acls = append(acls, &storage.ObjectAccessControl{
Email: serviceAccount,
Entity: "user-" + serviceAccount,
Role: "READER",
})

return &vfs.GSAcl{
Acl: acls,
}, nil
}

func Register() {
acls.RegisterPlugin("k8s.io/kops/acl/gce", &gcsAclStrategy{})
}
28 changes: 28 additions & 0 deletions pkg/acls/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package acls

import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/util/pkg/vfs"
)

// ACLStrategy is the interface implemented by ACL strategy providers
type ACLStrategy interface {
// GetACL returns the ACL if this strategy handles the vfs.Path, when writing for the specified cluster
GetACL(p vfs.Path, cluster *kops.Cluster) (vfs.ACL, error)
}
57 changes: 57 additions & 0 deletions pkg/acls/plugins.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package acls

import (
"fmt"
"sync"

"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/util/pkg/vfs"
)

var strategies map[string]ACLStrategy
var strategiesMutex sync.Mutex

// GetACL returns the ACL for the vfs.Path, by consulting all registered strategies
func GetACL(p vfs.Path, cluster *kops.Cluster) (vfs.ACL, error) {
strategiesMutex.Lock()
defer strategiesMutex.Unlock()

for k, strategy := range strategies {
acl, err := strategy.GetACL(p, cluster)
if err != nil {
return nil, fmt.Errorf("error from acl provider %q: %v", k, err)
}
if acl != nil {
return acl, nil
}
}
return nil, nil
}

// RegisterPlugin adds the strategy to the registered strategies
func RegisterPlugin(key string, strategy ACLStrategy) {
strategiesMutex.Lock()
defer strategiesMutex.Unlock()

if strategies == nil {
strategies = make(map[string]ACLStrategy)
}

strategies[key] = strategy
}
1 change: 1 addition & 0 deletions pkg/apis/kops/registry/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/acls:go_default_library",
"//pkg/apis/kops:go_default_library",
"//pkg/client/simple:go_default_library",
"//upup/pkg/fi/utils:go_default_library",
Expand Down
18 changes: 13 additions & 5 deletions pkg/apis/kops/registry/statestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package registry

import (
"fmt"
"k8s.io/kops/upup/pkg/fi/utils"
"k8s.io/kops/util/pkg/vfs"
"os"
"strings"

"k8s.io/kops/pkg/acls"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/upup/pkg/fi/utils"
"k8s.io/kops/util/pkg/vfs"
)

func ReadConfigDeprecated(configPath vfs.Path, config interface{}) error {
Expand Down Expand Up @@ -49,7 +52,7 @@ func ReadConfigDeprecated(configPath vfs.Path, config interface{}) error {

// WriteConfigDeprecated writes a config file as yaml.
// It is deprecated because it is unversioned, but it is still used, in particular for writing the completed config.
func WriteConfigDeprecated(configPath vfs.Path, config interface{}, writeOptions ...vfs.WriteOption) error {
func WriteConfigDeprecated(cluster *kops.Cluster, configPath vfs.Path, config interface{}, writeOptions ...vfs.WriteOption) error {
data, err := utils.YamlMarshal(config)
if err != nil {
return fmt.Errorf("error marshalling configuration: %v", err)
Expand All @@ -73,10 +76,15 @@ func WriteConfigDeprecated(configPath vfs.Path, config interface{}, writeOptions
}
}

acl, err := acls.GetACL(configPath, cluster)
if err != nil {
return err
}

if create {
err = configPath.CreateFile(data)
err = configPath.CreateFile(data, acl)
} else {
err = configPath.WriteFile(data)
err = configPath.WriteFile(data, acl)
}
if err != nil {
return fmt.Errorf("error writing configuration file %s: %v", configPath, err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/client/simple/api/clientset.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ func (c *RESTClientset) GetFederation(name string) (*kops.Federation, error) {

func (c *RESTClientset) SecretStore(cluster *kops.Cluster) (fi.SecretStore, error) {
namespace := restNamespaceForClusterName(cluster.Name)
return secrets.NewClientsetSecretStore(c.KopsClient, namespace), nil
return secrets.NewClientsetSecretStore(cluster, c.KopsClient, namespace), nil
}

func (c *RESTClientset) KeyStore(cluster *kops.Cluster) (fi.CAStore, error) {
namespace := restNamespaceForClusterName(cluster.Name)
return fi.NewClientsetCAStore(c.KopsClient, namespace), nil
return fi.NewClientsetCAStore(cluster, c.KopsClient, namespace), nil
}

func (c *RESTClientset) DeleteCluster(cluster *kops.Cluster) error {
Expand Down
1 change: 1 addition & 0 deletions pkg/client/simple/vfsclientset/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ go_library(
],
visibility = ["//visibility:public"],
deps = [
"//pkg/acls:go_default_library",
"//pkg/apis/kops:go_default_library",
"//pkg/apis/kops/registry:go_default_library",
"//pkg/apis/kops/v1alpha1:go_default_library",
Expand Down
7 changes: 3 additions & 4 deletions pkg/client/simple/vfsclientset/clientset.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ func (c *VFSClientset) ConfigBaseFor(cluster *kops.Cluster) (vfs.Path, error) {

// InstanceGroupsFor implements the InstanceGroupsFor method of simple.Clientset for a VFS-backed state store
func (c *VFSClientset) InstanceGroupsFor(cluster *kops.Cluster) kopsinternalversion.InstanceGroupInterface {
clusterName := cluster.Name
return newInstanceGroupVFS(c, clusterName)
return newInstanceGroupVFS(c, cluster)
}

func (c *VFSClientset) federations() kopsinternalversion.FederationInterface {
Expand Down Expand Up @@ -99,7 +98,7 @@ func (c *VFSClientset) SecretStore(cluster *kops.Cluster) (fi.SecretStore, error
return nil, err
}
basedir := configBase.Join("secrets")
return secrets.NewVFSSecretStore(basedir), nil
return secrets.NewVFSSecretStore(cluster, basedir), nil
}

func (c *VFSClientset) KeyStore(cluster *kops.Cluster) (fi.CAStore, error) {
Expand All @@ -108,7 +107,7 @@ func (c *VFSClientset) KeyStore(cluster *kops.Cluster) (fi.CAStore, error) {
return nil, err
}
basedir := configBase.Join("pki")
return fi.NewVFSCAStore(basedir), nil
return fi.NewVFSCAStore(cluster, basedir), nil
}

func DeleteAllClusterState(basePath vfs.Path) error {
Expand Down
Loading