Merge pull request #10458 from seventieskid/gcp-on-gitlab-using-docker

GCP add timeout to GCP metadata server read
This commit is contained in:
Megan Marsh 2021-01-15 14:51:28 -08:00 committed by GitHub
commit a9c4c056c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 63 deletions

View File

@ -70,9 +70,6 @@ type Driver interface {
// DeleteOSLoginSSHKey deletes the SSH public key for OSLogin with the given key.
DeleteOSLoginSSHKey(user, fingerprint string) error
// If packer is running on a GCE, derives the user from it for use with OSLogin.
GetOSLoginUserFromGCE() string
// Add to the instance metadata for the existing instance
AddToInstanceMetadata(zone string, name string, metadata map[string]string) error
}

View File

@ -10,11 +10,9 @@ import (
"errors"
"fmt"
"log"
"net/http"
"strings"
"time"
metadata "cloud.google.com/go/compute/metadata"
compute "google.golang.org/api/compute/v1"
"google.golang.org/api/option"
oslogin "google.golang.org/api/oslogin/v1"
@ -34,7 +32,6 @@ import (
type driverGCE struct {
projectId string
service *compute.Service
thisGCEUser string
osLoginService *oslogin.Service
ui packersdk.Ui
}
@ -136,8 +133,6 @@ func NewClientOptionGoogle(account *ServiceAccount, vaultOauth string, impersona
func NewDriverGCE(config GCEDriverConfig) (Driver, error) {
var thisGCEUser string
opts, err := NewClientOptionGoogle(config.Account, config.VaultOauthEngineName, config.ImpersonateServiceAccountName)
if err != nil {
return nil, err
@ -149,15 +144,6 @@ func NewDriverGCE(config GCEDriverConfig) (Driver, error) {
return nil, err
}
if metadata.OnGCE() {
log.Printf("[INFO] On GCE, capture service account for OSLogin...")
thisGCEUser, err = metadata.NewClient(&http.Client{}).Email("")
if err != nil {
return nil, err
}
}
log.Printf("[INFO] Instantiating OS Login client...")
osLoginService, err := oslogin.NewService(context.TODO(), opts)
if err != nil {
@ -170,7 +156,6 @@ func NewDriverGCE(config GCEDriverConfig) (Driver, error) {
return &driverGCE{
projectId: config.ProjectId,
service: service,
thisGCEUser: thisGCEUser,
osLoginService: osLoginService,
ui: config.Ui,
}, nil
@ -644,10 +629,6 @@ func (d *driverGCE) getPasswordResponses(zone, instance string) ([]windowsPasswo
return passwordResponses, nil
}
func (d *driverGCE) GetOSLoginUserFromGCE() string {
return d.thisGCEUser
}
func (d *driverGCE) ImportOSLoginSSHKey(user, sshPublicKey string) (*oslogin.LoginProfile, error) {
parent := fmt.Sprintf("users/%s", user)

View File

@ -94,8 +94,6 @@ type DriverMock struct {
AddToInstanceMetadataKVPairs map[string]string
AddToInstanceMetadataErrCh <-chan error
AddToInstanceMetadataErr error
OSLoginUserFromGCE string
}
func (d *DriverMock) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string, image_encryption_key *compute.CustomerEncryptionKey, imageStorageLocations []string) (<-chan *Image, <-chan error) {
@ -310,7 +308,3 @@ func (d *DriverMock) AddToInstanceMetadata(zone string, name string, metadata ma
return nil
}
func (d *DriverMock) GetOSLoginUserFromGCE() string {
return d.OSLoginUserFromGCE
}

View File

@ -5,7 +5,11 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
"net/http"
"time"
metadata "cloud.google.com/go/compute/metadata"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"google.golang.org/api/oauth2/v2"
@ -37,7 +41,7 @@ func (s *StepImportOSLoginSSHKey) Run(ctx context.Context, state multistep.State
}
// Are we running packer on a GCE ?
s.accountEmail = driver.GetOSLoginUserFromGCE()
s.accountEmail = getGCEUser()
if s.TokeninfoFunc == nil && s.accountEmail == "" {
s.TokeninfoFunc = tokeninfo
@ -140,3 +144,28 @@ func tokeninfo(ctx context.Context) (*oauth2.Tokeninfo, error) {
return svc.Tokeninfo().Context(ctx).Do()
}
// getGCEUser determines if we're running packer on a GCE, and if we are, gets the associated service account email for subsequent use with OSLogin.
// There are cases where we are running on a GCE, but the GCP metadata server isn't accessible. GitLab docker-engine runners are an edge case example of this.
// It makes little sense to run packer on GCP in this way, however, we defensively timeout in those cases, rather than abort.
func getGCEUser() string {
metadataCheckTimeout := 5 * time.Second
metadataCheckChl := make(chan string, 1)
go func() {
if metadata.OnGCE() {
GCEUser, _ := metadata.NewClient(&http.Client{}).Email("")
metadataCheckChl <- GCEUser
}
}()
select {
case thisGCEUser := <-metadataCheckChl:
log.Printf("[INFO] OSLogin: GCE service account %s will be used for identity", thisGCEUser)
return thisGCEUser
case <-time.After(metadataCheckTimeout):
log.Printf("[INFO] OSLogin: Could not derive a GCE service account from google metadata server after %s", metadataCheckTimeout)
return ""
}
}

View File

@ -150,37 +150,3 @@ func TestStepImportOSLoginSSHKey_withPrivateSSHKey(t *testing.T) {
t.Errorf("expected to not see a public key when using a dedicated private key, but got %q", pubKey)
}
}
func TestStepImportOSLoginSSHKey_onGCE(t *testing.T) {
state := testState(t)
d := state.Get("driver").(*DriverMock)
step := new(StepImportOSLoginSSHKey)
defer step.Cleanup(state)
fakeAccountEmail := "testing@packer.io"
config := state.Get("config").(*Config)
config.UseOSLogin = true
config.Comm.SSHPublicKey = []byte{'k', 'e', 'y'}
d.OSLoginUserFromGCE = fakeAccountEmail
if action := step.Run(context.Background(), state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v", action)
}
if step.accountEmail != fakeAccountEmail {
t.Fatalf("expected accountEmail to be %q but got %q", fakeAccountEmail, step.accountEmail)
}
pubKey, ok := state.GetOk("ssh_key_public_sha256")
if !ok {
t.Fatal("expected to see a public key")
}
sha256sum := sha256.Sum256(config.Comm.SSHPublicKey)
if pubKey != hex.EncodeToString(sha256sum[:]) {
t.Errorf("expected to see a matching public key, but got %q", pubKey)
}
}