Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Created November 9, 2019 19:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save salrashid123/e894e856c2851fe437eee5fc2b72c8ad to your computer and use it in GitHub Desktop.
Save salrashid123/e894e856c2851fe437eee5fc2b72c8ad to your computer and use it in GitHub Desktop.
Sample golang app that uses the Google CLoud Admin SDk to create a user and then add that user to a specific google group
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
)
/*
Sample golang app that uses the Google CLoud Admin SDk to create a user and then add that user to a specific google group
go run main.go --serviceAccountFile ../svc_account_with_dwd.json --cx C023zw3x8 --adminUser admin@esodemoapp2.com --firstname foo --lastname bar --email foobar@esodemoapp2.com --password dsfasdflbbbb --group group8_10@esodemoapp2.com
*/
var (
serviceAccountFile = flag.String("serviceAccountFile", "", "serviceAccountFile ID")
cx = flag.String("cx", "", "GSuites cx number")
adminUser = flag.String("adminUser", "", "GSuites adminUser")
firstName = flag.String("firstname", "", "user's firstname")
lastName = flag.String("lastname", "", "users lastname")
email = flag.String("email", "", "users email")
password = flag.String("password", "", "users password")
group = flag.String("group", "", "add user to group")
)
func main() {
flag.Parse()
if *serviceAccountFile == "" {
fmt.Fprintln(os.Stderr, "missing -serviceAccountFile flag")
flag.Usage()
os.Exit(2)
}
if *cx == "" {
fmt.Fprintln(os.Stderr, "missing -cx flag")
flag.Usage()
os.Exit(2)
}
if *adminUser == "" {
fmt.Fprintln(os.Stderr, "missing -adminUser flag")
flag.Usage()
os.Exit(2)
}
if *firstName == "" || *lastName == "" || *email == "" || *password == "" {
fmt.Fprintln(os.Stderr, "must specify firstname, lastname, email, password flag")
flag.Usage()
os.Exit(2)
}
serviceAccountJSON, err := ioutil.ReadFile(*serviceAccountFile)
if err != nil {
log.Fatal(err)
}
config, err := google.JWTConfigFromJSON(serviceAccountJSON,
admin.AdminDirectoryUserScope, admin.AdminDirectoryGroupScope,
)
//config.User = "adminapi@fabled-ray-104117.iam.gserviceaccount.com"
config.Subject = *adminUser
srv, err := admin.New(config.Client(context.Background()))
if err != nil {
log.Fatal(err)
}
insertResp, err := srv.Users.Insert(&admin.User{
Name: &admin.UserName{
GivenName: *firstName,
FamilyName: *lastName,
},
PrimaryEmail: *email,
Password: *password,
}).Do()
if err != nil {
log.Fatal(err)
}
fmt.Printf("inserUser %v", insertResp.CustomerId)
if *group != "" {
member := &admin.Member{
Email: *email,
}
insertResp, err := srv.Members.Insert(
*group, member,
).Do()
if err != nil {
log.Fatal(err)
}
fmt.Printf("add user to group ResponseCode %v", insertResp.Status)
}
usersReport, err := srv.Users.List().Customer(*cx).MaxResults(10).OrderBy("email").Do()
if err != nil {
log.Fatal(err)
}
if len(usersReport.Users) == 0 {
fmt.Print("No users found.\n")
} else {
fmt.Print("Users:\n")
for _, u := range usersReport.Users {
fmt.Printf("%s (%s)\n", u.PrimaryEmail, u.Name.FullName)
}
}
}
@StevenACoffman
Copy link

StevenACoffman commented May 19, 2021

@salrashid123 This is very helpful! We are interested in a golang equivalent of
etsy/Apotheosis or StillerMan/BreakGlass to allow temporary, self-service privilege escalation for GCP.

Ideally, developers would not have anything but rudimentary GCP privileges, and would make a logged request (with a reason and a duration) that would increase their privileges from a list of approved roles.

We could do this with group memberships, or we could assign the roles directly to the user. I'm curious if you are aware of an existing solution (preferably in Golang) or if you have any advice.

@salrashid123
Copy link
Author

@StevenACoffman

While you can assign roles to users on demand or add/remove users to/from groups using that API, managing firecall and on-demand access is pretty involved (and a bit risky ify ou don't remove/revoke access).

There are variations of roles/groups too for on-demand access: some custoemrs assigned a service account to a role and then granted a user temp iam role to imersonate that credential: https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials

or utilized "token broker" to deliver a limited one-time token https://cloud.google.com/iam/docs/downscoping-short-lived-credentials

yet others delegated management of firecall access to 3rd party systems like vault:

https://www.vaultproject.io/docs/secrets/gcp
https://github.com/salrashid123/vault_gcp#GCP-Vault-Secrets

in that, you get a temp access token from vault which has the requsite roles


This is kind of a long way to say, its not easy to roll firecall manually. That being said, do you happen to have a Google Cloud TAM or SCE or account team assigned? if so, could you send them an email about this and we can followup separtely

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment