Skip to content

Commit

Permalink
Merge pull request #1 from neo-technology/adam/token
Browse files Browse the repository at this point in the history
Get tokens from AzureAuthorityHost instead of IMDS
  • Loading branch information
adam-orosz authored Nov 3, 2022
2 parents 4185948 + 210f07e commit f82c95a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 118 deletions.
194 changes: 88 additions & 106 deletions common/oauthTokenManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,27 @@
package common

import (
"bufio"
"context"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
"time"

"golang.org/x/crypto/pkcs12"

"github.com/Azure/go-autorest/autorest/adal"
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
)

// ApplicationID represents 1st party ApplicationID for AzCopy.
Expand Down Expand Up @@ -75,6 +72,30 @@ type UserOAuthTokenManager struct {
stashedInfo *OAuthTokenInfo
}

// using this from https://github.com/Azure/go-autorest/blob/b3899c1057425994796c92293e931f334af63b4e/autorest/adal/token.go#L1055-L1067
// this struct works with the adal sdks used in clients and azure-cli token requests
type token struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`

// AAD returns expires_in as a string, ADFS returns it as an int
ExpiresIn json.Number `json:"expires_in"`
// expires_on can be in two formats, a UTC time stamp or the number of seconds.
ExpiresOn string `json:"expires_on"`
NotBefore json.Number `json:"not_before"`

Resource string `json:"resource"`
Type string `json:"token_type"`
}

// Environment variables injected in the pod
const (
AzureClientIDEnvVar = "AZURE_CLIENT_ID"
AzureTenantIDEnvVar = "AZURE_TENANT_ID"
AzureFederatedTokenFileEnvVar = "AZURE_FEDERATED_TOKEN_FILE" // #nosec
AzureAuthorityHostEnvVar = "AZURE_AUTHORITY_HOST"
)

// NewUserOAuthTokenManagerInstance creates a token manager instance.
func NewUserOAuthTokenManagerInstance(credCacheOptions CredCacheOptions) *UserOAuthTokenManager {
return &UserOAuthTokenManager{
Expand Down Expand Up @@ -794,115 +815,76 @@ func (credInfo *OAuthTokenInfo) GetNewTokenFromMSI(ctx context.Context) (*adal.T
if credInfo.Token.Resource != "" && credInfo.Token.Resource != targetResource {
targetResource = credInfo.Token.Resource
}

// Try Arc VM
req, resp, errArcVM := credInfo.queryIMDS(ctx, MSIEndpointArcVM, targetResource, IMDSAPIVersionArcVM)
if errArcVM != nil {
// Try Azure VM since there was an error in trying Arc VM
reqAzureVM, respAzureVM, errAzureVM := credInfo.queryIMDS(ctx, MSIEndpointAzureVM, targetResource, IMDSAPIVersionAzureVM)
if errAzureVM != nil {
var serr syscall.Errno
if errors.As(errArcVM, &serr) {
econnrefusedValue := -1
switch runtime.GOOS {
case "linux":
econnrefusedValue = int(syscall.ECONNREFUSED)
case "windows":
econnrefusedValue = WSAECONNREFUSED
}

if int(serr) == econnrefusedValue {
// If connection to Arc endpoint was refused
return nil, fmt.Errorf("please check whether MSI is enabled on this PC, to enable MSI please refer to https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm#enable-system-assigned-identity-on-an-existing-vm: %v", errAzureVM)
}

// A syscall error other than ECONNREFUSED, implies we could not get the HTTP response
return nil, fmt.Errorf("error communicating with Arc IMDS endpoint (%s): %v", MSIEndpointArcVM, errArcVM)
}

// queryIMDS failed, but not with a syscall error
// 1. Either it is an HTTP error, or
// 2. The HTTP request timed out
return nil, fmt.Errorf("invalid response received from Arc IMDS endpoint (%s), probably some unknown process listening: %v", MSIEndpointArcVM, errArcVM)
}

// Arc IMDS failed with error, but Azure IMDS succeeded
req, resp = reqAzureVM, respAzureVM
} else if !isValidArcResponse(resp) {
// Not valid response from ARC IMDS endpoint. Perhaps some other process listening on it. Try Azure IMDS endpoint as fallback option.
reqAzureVM, respAzureVM, errAzureVM := credInfo.queryIMDS(ctx, MSIEndpointAzureVM, targetResource, IMDSAPIVersionAzureVM)
if errAzureVM != nil {
// Neither Arc nor Azure VM IMDS endpoint available. Can't use MSI.
return nil, fmt.Errorf("invalid response received from Arc IMDS endpoint (%s), probably some unknown process listening. If this an Azure VM, please check whether MSI is enabled, to enable MSI please refer to https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm#enable-system-assigned-identity-on-an-existing-vm: %v", MSIEndpointArcVM, errAzureVM)
}

// Azure VM IMDS endpoint ok!
req, resp = reqAzureVM, respAzureVM
} else {
// Valid response received from ARC IMDS endpoint. Proceed with the next step.
challengeTokenPath := strings.Split(resp.Header["Www-Authenticate"][0], "=")[1]
// Open the file.
challengeTokenFile, fileErr := os.Open(challengeTokenPath)
if os.IsPermission(fileErr) {
switch runtime.GOOS {
case "linux":
return nil, fmt.Errorf("permission level inadequate to read Arc challenge token file %s. Make sure you are running AzCopy as a user who is a member of the \"himds\" group or is superuser.", challengeTokenPath)
case "windows":
return nil, fmt.Errorf("permission level inadequate to read Arc challenge token file %s. Make sure you are running AzCopy as a user who is a member of the \"local Administrators\" group or the \"Hybrid Agent Extension Applications\" group.", challengeTokenPath)
default:
return nil, fmt.Errorf("error occurred while opening file %s in unsupported GOOS %s: %v", challengeTokenPath, runtime.GOOS, fileErr)
}
} else if fileErr != nil {
return nil, fmt.Errorf("error occurred while opening file %s: %v", challengeTokenPath, fileErr)
}

defer challengeTokenFile.Close()

// Create a new Reader for the file.
reader := bufio.NewReader(challengeTokenFile)
challengeToken, fileErr := reader.ReadString('\n')
if fileErr != nil && fileErr != io.EOF {
return nil, fmt.Errorf("error occurred while reading file %s: %v", challengeTokenPath, fileErr)
}

req.Header.Set("Authorization", "Basic "+challengeToken)

resp, errArcVM = msiTokenHTTPClient.Do(req)
if errArcVM != nil {
return nil, fmt.Errorf("failed to query token from Arc IMDS endpoint: %v", errArcVM)
}
// doTokenRequest was copied from https://github.com/Azure/azure-workload-identity/blob/main/pkg/proxy/proxy.go
// this makes it possible to use azcopy with Workload Identity, without requiring a proxy container
token, err := doTokenRequest(ctx,
os.Getenv(AzureClientIDEnvVar),
targetResource,
os.Getenv(AzureTenantIDEnvVar),
os.Getenv(AzureAuthorityHostEnvVar),
)
if err != nil {
return nil, fmt.Errorf("failed to get token: %s", err)
}
return &adal.Token{
AccessToken: token.AccessToken,
Resource: token.Resource,
Type: token.Type,
ExpiresOn: json.Number(token.ExpiresOn),
ExpiresIn: token.ExpiresIn,
NotBefore: token.NotBefore,
RefreshToken: token.RefreshToken,
}, nil
}

func doTokenRequest(ctx context.Context, clientID, resource, tenantID, authorityHost string) (*token, error) {
tokenFilePath := os.Getenv(AzureFederatedTokenFileEnvVar)
cred := confidential.NewCredFromAssertionCallback(
func(
context.Context,
confidential.AssertionRequestOptions,
) (string, error) {
return readJWTFromFS(tokenFilePath)
})

confidentialClientApp, err := confidential.New(clientID, cred,
confidential.WithAuthority(fmt.Sprintf("%s%s/oauth2/token", authorityHost, tenantID)))
if err != nil {
return nil, fmt.Errorf("failed to create confidential client app: %s", err)
}

defer func() { // resp and Body should not be nil
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}()

// Check if the status code indicates success
// The request returns 200 currently, add 201 and 202 as well for possible extension.
if !(HTTPResponseExtension{Response: resp}).IsSuccessStatusCode(http.StatusOK, http.StatusCreated, http.StatusAccepted) {
return nil, fmt.Errorf("failed to get token from msi, status code: %v", resp.StatusCode)
// ref: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/747
// For MSAL (v2.0 endpoint) asking an access token for a resource that accepts a v1.0 access token,
// Azure AD parses the desired audience from the requested scope by taking everything before the
// last slash and using it as the resource identifier.
// For example, if the scope is "https://vault.azure.net/.default", the resource identifier is "https://vault.azure.net".
// If the scope is "http://database.windows.net//.default", the resource identifier is "http://database.windows.net/".
scope := resource
if !strings.HasPrefix(scope, "/.default") {
scope = scope + "/.default"
}

b, err := ioutil.ReadAll(resp.Body)
result, err := confidentialClientApp.AcquireTokenByCredential(ctx, []string{scope})
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to acquire token: %s", err)
}

result := &adal.Token{}
if len(b) > 0 {
b = ByteSliceExtension{ByteSlice: b}.RemoveBOM()
// Unmarshal will give an error for Go version >= 1.14 for a field with blank values. Arc-server endpoint API returns blank for "not_before" field.
// TODO: Remove fixup once Arc team fixes the issue.
b = fixupTokenJson(b)
if err := json.Unmarshal(b, result); err != nil {
return nil, fmt.Errorf("failed to unmarshal response body: %v", err)
}
} else {
return nil, errors.New("failed to get token from msi")
}
return &token{
AccessToken: result.AccessToken,
Resource: resource,
Type: "Bearer",
// There is a difference in parsing between the azure sdks and how azure-cli works
// Using the unix time to be consistent with response from IMDS which works with
// all the clients.
ExpiresOn: strconv.FormatInt(result.ExpiresOn.UTC().Unix(), 10),
}, nil
}

return result, nil
func readJWTFromFS(tokenFilePath string) (string, error) {
token, err := os.ReadFile(tokenFilePath)
if err != nil {
return "", err
}
return string(token), nil
}

// RefreshTokenWithUserCredential gets new token with user credential through refresh.
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/Azure/azure-storage-blob-go v0.15.0
github.com/Azure/azure-storage-file-go v0.6.1-0.20201111053559-3c1754dc00a5
github.com/Azure/go-autorest/autorest/adal v0.9.18
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0
github.com/JeffreyRichter/enum v0.0.0-20180725232043-2567042f9cda
github.com/danieljoos/wincred v1.1.2
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
Expand Down Expand Up @@ -36,13 +37,14 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-ini/ini v1.66.4 // indirect
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand Down
21 changes: 10 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,9 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
cloud.google.com/go/storage v1.21.0 h1:HwnT2u2D309SFDHQII6m18HlrCi3jAXhUMTLOWXYH14=
cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220420205509-9c760f3e9499 h1:eVXzrNOutCSxn7gYn2Tb2alO/D41vX6EyDoRhByS4zc=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220420205509-9c760f3e9499/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220425205405-09e6f201e1e4 h1:hDJImUzpTAeIw/UasFUUDB/+UsZm5Q/6x2/jKKvEUiw=
github.com/Azure/azure-pipeline-go v0.2.4-0.20220425205405-09e6f201e1e4/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220307213743-78b465951faf h1:81jHLpY81IPdZqBzsnudRpQM1E9xk+ZzBhhJm7BEvcY=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220307213743-78b465951faf/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220418210520-914dace75d43 h1:/yh9OPVjemL4n8CaXc+GpFTvSlotRFj2HXJIgLo2gG8=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220418210520-914dace75d43/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220418220008-28ac0a48144e h1:uGef/l7KHdWy6XTwhnEB4IhJEisPLe0TDfLVthiVL04=
github.com/Azure/azure-storage-blob-go v0.13.1-0.20220418220008-28ac0a48144e/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk=
github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58=
github.com/Azure/azure-storage-file-go v0.6.1-0.20201111053559-3c1754dc00a5 h1:aHEvBM4oXIWSTOVdL55nCYXO0Cl7ie3Ui5xMQhLVez8=
Expand All @@ -86,6 +77,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 h1:VgSJlZH5u0k2qxSpqyghcFQKmvYckj46uymKK5XzkBM=
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/JeffreyRichter/enum v0.0.0-20180725232043-2567042f9cda h1:NOo6+gM9NNPJ3W56nxOKb4164LEw094U0C8zYQM8mQU=
Expand Down Expand Up @@ -134,8 +127,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-ini/ini v1.66.4 h1:dKjMqkcbkzfddhIhyglTPgMoJnkvmG+bSLrU9cTHc5M=
github.com/go-ini/ini v1.66.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
Expand Down Expand Up @@ -207,6 +200,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
Expand Down Expand Up @@ -236,14 +230,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-ieproxy v0.0.3 h1:YkaHmK1CzE5C4O7A3hv3TCbfNDPSCf0RKZFX+VhBeYk=
github.com/mattn/go-ieproxy v0.0.3/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=
github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -441,6 +439,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down

0 comments on commit f82c95a

Please sign in to comment.