Added basic support for service principal login, run ACI e2e tests with it

This commit is contained in:
Guillaume Tardif 2020-06-29 17:57:06 +02:00
parent 169e3a9b1f
commit eda438aaed
6 changed files with 67 additions and 1 deletions

View File

@ -55,3 +55,10 @@ jobs:
- name: E2E Test
run: make e2e-local
- name: ACI e2e Test
env:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
run: make e2e-aci

View File

@ -31,6 +31,7 @@ import (
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
auth2 "github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/Azure/go-autorest/autorest/azure/cli"
"github.com/Azure/go-autorest/autorest/date"
"github.com/pkg/errors"
@ -93,6 +94,31 @@ func newAzureLoginServiceFromPath(tokenStorePath string, helper apiHelper) (Azur
}, nil
}
// LoginFromServicePrincipal login with clientId / clientSecret from a previously created service principal
func (login AzureLoginService) LoginFromServicePrincipal(clientID string, clientSecret string, tenantID string) error {
// Tried with auth2.NewUsernamePasswordConfig() but could not make this work with username / password, setting this for CI with clientID / clientSecret
creds := auth2.NewClientCredentialsConfig(clientID, clientSecret, tenantID)
spToken, err := creds.ServicePrincipalToken()
if err != nil {
return errors.Wrapf(errdefs.ErrLoginFailed, "could not login with service principal: %s", err)
}
err = spToken.Refresh()
if err != nil {
return errors.Wrapf(errdefs.ErrLoginFailed, "could not login with service principal: %s", err)
}
token, err := spToOAuthToken(spToken.Token())
if err != nil {
return errors.Wrapf(errdefs.ErrLoginFailed, "could not read service principal token expiry: %s", err)
}
loginInfo := TokenInfo{TenantID: tenantID, Token: token}
if err := login.tokenStore.writeLoginInfo(loginInfo); err != nil {
return errors.Wrapf(errdefs.ErrLoginFailed, "could not store login info: %s", err)
}
return nil
}
// Login performs an Azure login through a web browser
func (login AzureLoginService) Login(ctx context.Context) error {
queryCh := make(chan localResponse, 1)
@ -179,6 +205,21 @@ func toOAuthToken(token azureToken) oauth2.Token {
return oauthToken
}
func spToOAuthToken(token adal.Token) (oauth2.Token, error) {
expiresIn, err := token.ExpiresIn.Int64()
if err != nil {
return oauth2.Token{}, err
}
expireTime := time.Now().Add(time.Duration(expiresIn) * time.Second)
oauthToken := oauth2.Token{
RefreshToken: token.RefreshToken,
AccessToken: token.AccessToken,
Expiry: expireTime,
TokenType: token.Type,
}
return oauthToken, nil
}
// NewAuthorizerFromLogin creates an authorizer based on login access token
func NewAuthorizerFromLogin() (autorest.Authorizer, error) {
return newAuthorizerFromLoginStorePath(getTokenStorePath())

View File

@ -3,9 +3,10 @@ package mobycli
import (
"testing"
"github.com/docker/api/tests/framework"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/suite"
"github.com/docker/api/tests/framework"
)
type MobyExecSuite struct {

1
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/Azure/azure-storage-file-go v0.7.0
github.com/Azure/go-autorest/autorest v0.11.0
github.com/Azure/go-autorest/autorest/adal v0.9.0
github.com/Azure/go-autorest/autorest/azure/auth v0.5.0
github.com/Azure/go-autorest/autorest/azure/cli v0.4.0
github.com/Azure/go-autorest/autorest/date v0.3.0
github.com/Azure/go-autorest/autorest/to v0.4.0

2
go.sum
View File

@ -18,6 +18,8 @@ github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKn
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.9.0 h1:SigMbuFNuKgc1xcGhaeapbh+8fgsu+GxgDRFyg7f5lM=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 h1:nSMjYIe24eBYasAIxt859TxyXef/IqoH+8/g4+LmcVs=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 h1:Ml+UCrnlKD+cJmSzrZ/RDcDw86NjkRUpnFh7V5JUhzU=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=

View File

@ -20,10 +20,12 @@ import (
"context"
"fmt"
"net/url"
"os"
"strings"
"testing"
"github.com/docker/api/azure"
"github.com/docker/api/azure/login"
"github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/resources/mgmt/resources"
azure_storage "github.com/Azure/azure-sdk-for-go/profiles/2019-03-01/storage/mgmt/storage"
@ -69,6 +71,18 @@ func (s *E2eACISuite) TestContextDefault() {
}
func (s *E2eACISuite) TestACIBackend() {
It("Logs in azure using service principal credentials", func() {
login, err := login.NewAzureLoginService()
Expect(err).To(BeNil())
// in order to create new service principal and get these 3 values : `az ad sp create-for-rbac --name 'TestServicePrincipal' --sdk-auth`
clientID := os.Getenv("AZURE_CLIENT_ID")
clientSecret := os.Getenv("AZURE_CLIENT_SECRET")
tenantID := os.Getenv("AZURE_TENANT_ID")
err = login.LoginFromServicePrincipal(clientID, clientSecret, tenantID)
Expect(err).To(BeNil())
})
It("creates a new aci context for tests", func() {
setupTestResourceGroup(resourceGroupName)
helper := azure.NewACIResourceGroupHelper()