Skip to content

Commit 93d0479

Browse files
valyankilyanValentin Kiel
andauthored
Support Instance SA authentication (#19)
* add fetch token * move token fetch to yc client init * remove unnecessary and dangerous outputs * linter * ycsdk instance sa instead of curl yc-token * remove unused code Co-authored-by: Valentin Kiel <val-kiel@yandex-team.ru>
1 parent 02e4504 commit 93d0479

File tree

6 files changed

+56
-39
lines changed

6 files changed

+56
-39
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ $ docker-machine create \
3333

3434
## Options
3535

36+
If you haven't specified yc-token nor yc-service-account-key-file it will try to get Instance Service Account.
37+
3638
- `--yandex-cloud-id`: Cloud ID
3739
- `--yandex-cores`: Count of virtual CPUs
3840
- `--yandex-core-fraction`: Core fraction
@@ -90,4 +92,4 @@ $ docker-machine create \
9092
| `--yandex-use-internal-ip` | YC_USE_INTERNAL_IP | false |
9193
| `--yandex-userdata` | YC_USERDATA | |
9294
| `--yandex-zone` | YC_ZONE | ru-central1-a |
93-
---
95+
---

driver/client.go

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"strings"
87

98
"github.com/c2h5oh/datasize"
109
"github.com/docker/machine/libmachine/log"
1110
"github.com/google/uuid"
1211
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
1312
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
1413
ycsdk "github.com/yandex-cloud/go-sdk"
15-
"github.com/yandex-cloud/go-sdk/iamkey"
1614
"github.com/yandex-cloud/go-sdk/pkg/requestid"
1715
"github.com/yandex-cloud/go-sdk/pkg/retry"
1816
"google.golang.org/grpc"
@@ -139,28 +137,9 @@ func prepareInstanceCreateRequest(d *Driver, imageID string) *compute.CreateInst
139137
}
140138

141139
func NewYCClient(d *Driver) (*YCClient, error) {
142-
if d.Token != "" && d.ServiceAccountKeyFile != "" {
143-
return nil, errors.New("one of token or service account key file must be specified, not both")
144-
}
145-
146-
var credentials ycsdk.Credentials
147-
switch {
148-
case d.Token != "":
149-
if strings.HasPrefix(d.Token, "t1.") && strings.Count(d.Token, ".") == 2 {
150-
credentials = ycsdk.NewIAMTokenCredentials(d.Token)
151-
} else {
152-
credentials = ycsdk.OAuthToken(d.Token)
153-
}
154-
case d.ServiceAccountKeyFile != "":
155-
key, err := iamkey.ReadFromJSONFile(d.ServiceAccountKeyFile)
156-
if err != nil {
157-
return nil, err
158-
}
159-
160-
credentials, err = ycsdk.ServiceAccountKey(key)
161-
if err != nil {
162-
return nil, err
163-
}
140+
credentials, err := d.Credentials()
141+
if err != nil {
142+
return nil, err
164143
}
165144

166145
config := ycsdk.Config{

driver/driver.go

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import (
55
"context"
66
"errors"
77
"fmt"
8-
"io/ioutil"
98
"net"
109
"os"
1110
"strings"
1211
"text/template"
12+
"time"
1313

1414
"github.com/docker/machine/libmachine/drivers"
1515
"github.com/docker/machine/libmachine/log"
@@ -19,6 +19,8 @@ import (
1919
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
2020
"github.com/yandex-cloud/go-genproto/yandex/cloud/resourcemanager/v1"
2121
"github.com/yandex-cloud/go-genproto/yandex/cloud/vpc/v1"
22+
ycsdk "github.com/yandex-cloud/go-sdk"
23+
"github.com/yandex-cloud/go-sdk/iamkey"
2224
)
2325

2426
type Driver struct {
@@ -61,7 +63,7 @@ const (
6163
defaultDiskSize = 20
6264
defaultDiskType = "network-hdd"
6365
defaultEndpoint = "api.cloud.yandex.net:443"
64-
defaultImageFamily = "ubuntu-1604-lts"
66+
defaultImageFamily = "ubuntu-2004-lts"
6567
defaultImageFolderID = StandardImagesFolderID
6668
defaultMemory = 1
6769
defaultPlatformID = "standard-v1"
@@ -245,13 +247,6 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error {
245247
d.ServiceAccountKeyFile = flags.String("yandex-sa-key-file")
246248
d.Token = flags.String("yandex-token")
247249

248-
switch {
249-
case d.Token != "" && d.ServiceAccountKeyFile != "":
250-
return fmt.Errorf("Yandex.Cloud driver requires one of token or service account key file, not both")
251-
case d.Token == "" && d.ServiceAccountKeyFile == "":
252-
return fmt.Errorf("A token or service account key file must be specified")
253-
}
254-
255250
d.Cores = flags.Int("yandex-cores")
256251
d.CoreFraction = flags.Int("yandex-core-fraction")
257252
d.DiskSize = flags.Int("yandex-disk-size")
@@ -345,7 +340,7 @@ func (d *Driver) Create() error {
345340
return err
346341
}
347342

348-
publicKey, err := ioutil.ReadFile(d.publicSSHKeyPath())
343+
publicKey, err := os.ReadFile(d.publicSSHKeyPath())
349344
if err != nil {
350345
return err
351346
}
@@ -610,7 +605,7 @@ func (d *Driver) prepareUserData(publicKey string) (string, error) {
610605

611606
if d.UserDataFile != "" {
612607
log.Infof("Use provided file %q with user-data", d.UserDataFile)
613-
buf, err := ioutil.ReadFile(d.UserDataFile)
608+
buf, err := os.ReadFile(d.UserDataFile)
614609
if err != nil {
615610
return "", err
616611
}
@@ -623,6 +618,45 @@ func (d *Driver) prepareUserData(publicKey string) (string, error) {
623618
return userData, nil
624619
}
625620

621+
func (d *Driver) Credentials() (ycsdk.Credentials, error) {
622+
if d.ServiceAccountKeyFile != "" && d.Token != "" {
623+
return nil, fmt.Errorf("only one of 'token' or 'sa-key-file' should be specified")
624+
}
625+
626+
if d.ServiceAccountKeyFile != "" {
627+
key, err := iamkey.ReadFromJSONFile(d.ServiceAccountKeyFile)
628+
if err != nil {
629+
return nil, err
630+
}
631+
return ycsdk.ServiceAccountKey(key)
632+
}
633+
634+
if d.Token != "" {
635+
if strings.HasPrefix(d.Token, "t1.") && strings.Count(d.Token, ".") == 2 {
636+
return ycsdk.NewIAMTokenCredentials(d.Token), nil
637+
}
638+
return ycsdk.OAuthToken(d.Token), nil
639+
}
640+
641+
if sa := ycsdk.InstanceServiceAccount(); checkServiceAccountAvailable(context.Background(), sa) {
642+
fmt.Println("Trying to get Instance Service Account.")
643+
return sa, nil
644+
}
645+
646+
return nil, fmt.Errorf("one of 'token' or 'sa-key-file' should be specified; if you are inside compute instance, you can attach service account to it in order to authenticate via instance service account")
647+
}
648+
649+
func checkServiceAccountAvailable(ctx context.Context, sa ycsdk.NonExchangeableCredentials) bool {
650+
dialer := net.Dialer{Timeout: 50 * time.Millisecond}
651+
conn, err := dialer.Dial("tcp", net.JoinHostPort(ycsdk.InstanceMetadataAddr, "80"))
652+
if err != nil {
653+
return false
654+
}
655+
_ = conn.Close()
656+
_, err = sa.IAMToken(ctx)
657+
return err == nil
658+
}
659+
626660
func defaultUserData(sshUserName, sshPublicKey string) (string, error) {
627661
type templateData struct {
628662
SSHUserName string

driver/driver_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package driver
22

33
import (
4-
"io/ioutil"
4+
"os"
55
"testing"
66

77
"github.com/stretchr/testify/require"
@@ -78,7 +78,7 @@ users:
7878
require.Error(t, e, "error expected")
7979
} else {
8080
require.NoError(t, e, "no error expected, got one")
81-
content, err := ioutil.ReadFile("testdata/" + tt.golden + ".golden")
81+
content, err := os.ReadFile("testdata/" + tt.golden + ".golden")
8282
if err != nil {
8383
t.Fatalf("Error loading golden file: %s", err)
8484
}

helper/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"fmt"
5+
56
"github.com/docker/machine/libmachine/mcnflag"
67
"github.com/yandex-cloud/docker-machine-driver-yandex/driver"
78
)

main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package main
33
import (
44
"flag"
55
"fmt"
6+
"os"
7+
68
"github.com/docker/machine/libmachine/drivers/plugin"
79
"github.com/yandex-cloud/docker-machine-driver-yandex/driver"
8-
"os"
910
)
1011

1112
// Version will be added once we start the build process

0 commit comments

Comments
 (0)