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

Use gcloud secrets instead of git-crypt for groups #821

Merged
merged 2 commits into from
Apr 30, 2020
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
26 changes: 26 additions & 0 deletions audit/audit-gcp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,32 @@ gcloud \
#### gcloud alpha monitoring channels list > "projects/${PROJECT}/services/monitoring.channels.json"
#### gcloud alpha monitoring channel-descriptors list > "projects/${PROJECT}/services/monitoring.channel-descriptors.json"
;;
secretmanager)
gcloud \
secrets list \
--project=k8s-gsuite \
--format="value(name)" \
| while read -r SECRET; do
path="projects/${PROJECT}/secrets/${SECRET}"
mkdir -p "${path}"
gcloud \
secrets describe "${SECRET}" \
--project="${PROJECT}" \
--format=json \
> "${path}/description.json"
gcloud \
secrets versions list "${SECRET}" \
--project="${PROJECT}" \
--format=json \
> "${path}/versions.json"
gcloud \
secrets get-iam-policy "${SECRET}" \
--project="${PROJECT}" \
--format=json \
| jq 'del(.etag)' \
> "${path}/iam.json"
done
;;
storage-api)
gsutil ls -p "${PROJECT}" \
| awk -F/ '{print $3}' \
Expand Down
2 changes: 0 additions & 2 deletions groups/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,4 @@ default: run

.PHONY: run
run:
git-crypt unlock
GO111MODULE=on go run reconcile.go $(runargs)
git-crypt lock
4 changes: 2 additions & 2 deletions groups/config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Configuration for the kubernetes.io Google Groups setup

# file path of the google groups service account token
token-file: k8s-gsuite-1781c2662b57.json
# Secret version of the service account key to use
secret-version: projects/k8s-gsuite/secrets/gsuite-groups-manager_key/versions/latest

# Email id of the bot service account
bot-id: wg-k8s-infra-api@kubernetes.io
Expand Down
8 changes: 5 additions & 3 deletions groups/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ module k8s.io/k8s.io/groups
go 1.12

require (
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
google.golang.org/api v0.9.0
cloud.google.com/go v0.56.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
google.golang.org/api v0.20.0
google.golang.org/genproto v0.0.0-20200429120912-1f37eeb960b2
gopkg.in/yaml.v2 v2.2.2
k8s.io/test-infra v0.0.0-20191024183346-202cefeb6ff5
)
152 changes: 152 additions & 0 deletions groups/go.sum

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions groups/groups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,18 @@ groups:
- spiffxp@google.com
- thockin@google.com

- email-id: k8s-infra-group-admins@kubernetes.io
name: Group Administrators for kubernetes.io
description: |-
People trusted to admin kubernetes.io google groups by
running the groups reconciler
settings:
ReconcileMembers: "true"
members:
- cblecker@gmail.com
- davanum@gmail.com
- spiffxp@google.com
- thockin@google.com
#
# Push groups: k8s-infra-push-*
#
Expand Down
Binary file removed groups/k8s-gsuite-1781c2662b57.json
Binary file not shown.
37 changes: 28 additions & 9 deletions groups/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ import (
"reflect"
"time"

secretmanager "cloud.google.com/go/secretmanager/apiv1"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
"google.golang.org/api/admin/directory/v1"
"google.golang.org/api/googleapi"
"google.golang.org/api/groupssettings/v1"
secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
"gopkg.in/yaml.v2"

"k8s.io/test-infra/pkg/genyaml"
Expand All @@ -43,8 +45,8 @@ type Config struct {
// the email id for the bot/service account
BotID string `yaml:"bot-id"`

// the file with the authentication information
TokenFile string `yaml:"token-file,omitempty"`
// the gcloud secret containing a service account key to authenticate with
SecretVersion string `yaml:"secret-version,omitempty"`

// the file with the groups/members information
GroupsFile string `yaml:"groups-file,omitempty"`
Expand Down Expand Up @@ -107,18 +109,14 @@ func main() {
log.Fatal(err)
}

jsonCredentials, err := ioutil.ReadFile(config.TokenFile)
if err != nil {
log.Fatal(err)
}
serviceAccountKey, err := accessSecretVersion(config.SecretVersion)

credential, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryUserReadonlyScope,
credential, err := google.JWTConfigFromJSON(serviceAccountKey, admin.AdminDirectoryUserReadonlyScope,
admin.AdminDirectoryGroupScope,
admin.AdminDirectoryGroupMemberScope,
groupssettings.AppsGroupsSettingsScope)
if err != nil {
log.Fatalf("Unable to parse client secret file to config: %v\n. "+
"Please run 'git-crypt unlock'", err)
log.Fatalf("Unable to authenticate using key in secret-version %s, %v", config.SecretVersion, err)
}
credential.Subject = config.BotID

Expand Down Expand Up @@ -621,3 +619,24 @@ func deepCopySettings(a, b interface{}) {
byt, _ := json.Marshal(a)
json.Unmarshal(byt, b)
}

// accessSecretVersion accesses the payload for the given secret version if one exists
// secretVersion is of the form projects/{project}/secrets/{secret}/versions/{version}
func accessSecretVersion(secretVersion string) ([]byte, error) {
ctx := context.Background()
client, err := secretmanager.NewClient(ctx)
if err != nil {
return nil, fmt.Errorf("failed to create secretmanager client: %v", err)
}

req := &secretmanagerpb.AccessSecretVersionRequest{
Name: secretVersion,
}

result, err := client.AccessSecretVersion(ctx, req)
if err != nil {
return nil, fmt.Errorf("failed to access secret version: %v", err)
}

return result.Payload.Data, nil
}
24 changes: 24 additions & 0 deletions infra/gcp/ensure-gsuite.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ GSUITE_SVCACCT="gsuite-groups-manager"
# delegation.
GSUITE_USER="wg-k8s-infra-api@kubernetes.io"

# The group of people authorized to access the secret that contains
# the service account key
GSUITE_GROUP_ADMINS="k8s-infra-group-admins@kubernetes.io"


color 6 "Ensuring project exists: ${PROJECT}"
ensure_project "${PROJECT}"
Expand All @@ -55,13 +59,33 @@ enable_api "${PROJECT}" admin.googleapis.com
color 6 "Enabling the GSuite groups API"
enable_api "${PROJECT}" groupssettings.googleapis.com

color 6 "Enabling the Secret Manager API"
enable_api "${PROJECT}" secretmanager.googleapis.com

# Create a service account for gsuite to grant access to.
color 6 "Creating service account for ${GSUITE_SVCACCT}"
ensure_service_account \
"${PROJECT}" \
"${GSUITE_SVCACCT}" \
"Grants access to the googlegroups API in kubernetes.io GSuite"

# Ensure the service account has a key in a secret accessible by the right people
if ! gcloud --project="${PROJECT}" \
secrets describe "${GSUITE_SVCACCT}_key" >/dev/null 2>&1; then
color 6 "A human with admin privileges needs to run the following:"
color 4 " gcloud iam service-accounts keys create tmp.json --project=${PROJECT} \\"
color 4 " --iam-account=$(svc_acct_email "${PROJECT}" "${GSUITE_SVCACCT}") && \\"
color 4 " gcloud secrets create --project=${PROJECT} --replication-policy=automatic \\"
color 4 " --data-file=tmp.json ${GSUITE_SVCACCT}_key && \\"
color 4 " rm tmp.json"
else
color 6 "Empowering ${GSUITE_GROUP_ADMINS} to access the ${GSUITE_SVCACCT}_key secret"
gcloud --project="${PROJECT}" \
secrets add-iam-policy-binding "${GSUITE_SVCACCT}_key" \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of add, should this be a "set"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point. We haven't used set-iam-policy in these scripts yet. I'd like to do this as a followup as I have some groups reconciliation to do for some other PRs

--member="group:${GSUITE_GROUP_ADMINS}" \
--role="roles/secretmanager.secretAccessor"
fi

# Grant project owner for now because I have no idea exactly which specific
# permissions are needed, and the UI is really not helping.
color 6 "Empowering ${GSUITE_USER}"
Expand Down