Skip to content

Commit

Permalink
Merge pull request #194 from SomtochiAma/gcp-autologin
Browse files Browse the repository at this point in the history
Get credentials from GCP/Azure when needed
  • Loading branch information
stefanprodan authored Jan 20, 2022
2 parents 86d5c29 + fcd6c92 commit 4ca33b4
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 7 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
# azure-sdk-for-go requires 1.16 or greater
- uses: actions/setup-go@v2
with:
go-version: '1.17.x'
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
Expand Down
146 changes: 145 additions & 1 deletion controllers/imagerepository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"regexp"
Expand All @@ -46,6 +47,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/predicate"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecr"
Expand All @@ -56,6 +60,7 @@ import (
"github.com/fluxcd/pkg/runtime/predicates"

imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
"github.com/fluxcd/image-reflector-controller/internal/azure"
)

// These are intended to match the keys used in e.g.,
Expand All @@ -80,7 +85,9 @@ type ImageRepositoryReconciler struct {
DatabaseReader
}

AwsAutoLogin bool // automatically attempt to get credentials for images in ECR
AwsAutoLogin bool // automatically attempt to get credentials for images in ECR
GcpAutoLogin bool // automatically attempt to get credentials for images in GCP
AzureAutoLogin bool // automatically attempt to get credentials for images in ACR
}

type ImageRepositoryReconcilerOptions struct {
Expand All @@ -91,6 +98,12 @@ type dockerConfig struct {
Auths map[string]authn.AuthConfig
}

type gceToken struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
TokenType string `json:"token_type"`
}

// +kubebuilder:rbac:groups=image.toolkit.fluxcd.io,resources=imagerepositories,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=image.toolkit.fluxcd.io,resources=imagerepositories/status,verbs=get;update;patch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch
Expand Down Expand Up @@ -246,6 +259,53 @@ func getAwsECRLoginAuth(accountId, awsEcrRegion string) (authn.AuthConfig, error
return authConfig, nil
}

// getGCRLoginAuth obtains authentication for the image by
// getting a token from the metadata API on GCP. This assumes that
// the pod has right to pull the image which would be the case if it
// is hosted on GCP. It works with both service account and workload identity
// enabled clusters.
func getGCRLoginAuth(ctx context.Context) (authn.AuthConfig, error) {
var authConfig authn.AuthConfig
const gcpDefaultTokenURL = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"

request, err := http.NewRequestWithContext(ctx, http.MethodGet, gcpDefaultTokenURL, nil)
if err != nil {
return authConfig, err
}

request.Header.Add("Metadata-Flavor", "Google")

client := &http.Client{}
response, err := client.Do(request)
if err != nil {
return authConfig, err
}

if response.StatusCode != http.StatusOK {
return authConfig, fmt.Errorf("unexpected status from metadata service: %s", response.Status)
}

var accessToken gceToken
decoder := json.NewDecoder(response.Body)
if err := decoder.Decode(&accessToken); err != nil {
return authConfig, err
}

if _, err := io.Copy(io.Discard, response.Body); err != nil {
return authConfig, err
}

if err := response.Body.Close(); err != nil {
return authConfig, err
}

authConfig = authn.AuthConfig{
Username: "oauth2accesstoken",
Password: accessToken.AccessToken,
}
return authConfig, nil
}

func (r *ImageRepositoryReconciler) scan(ctx context.Context, imageRepo *imagev1.ImageRepository, ref name.Reference) error {
timeout := imageRepo.GetTimeout()
ctx, cancel := context.WithTimeout(ctx, timeout)
Expand Down Expand Up @@ -297,6 +357,46 @@ func (r *ImageRepositoryReconciler) scan(ctx context.Context, imageRepo *imagev1
} else {
ctrl.LoggerFrom(ctx).Info("No image credentials secret referenced, and ECR authentication is not enabled. To enable, set the controller flag --aws-autologin-for-ecr")
}
} else if hostIsGoogleContainerRegistry(ref.Context().RegistryStr()) {
if r.GcpAutoLogin {
ctrl.LoggerFrom(ctx).Info("Logging in to GCP GCR for " + imageRepo.Spec.Image)
authConfig, err := getGCRLoginAuth(ctx)
if err != nil {
ctrl.LoggerFrom(ctx).Info("error logging into GCP " + err.Error())
imagev1.SetImageRepositoryReadiness(
imageRepo,
metav1.ConditionFalse,
meta.ReconciliationFailedReason,
err.Error(),
)
return err
}

auth := authn.FromConfig(authConfig)
options = append(options, remote.WithAuth(auth))
} else {
ctrl.LoggerFrom(ctx).Info("No image credentials secret referenced, and GCR authentication is not enabled. To enable, set the controller flag --gcp-autologin-for-gcr")
}
} else if hostIsAzureContainerRegistry(ref.Context().RegistryStr()) {
if r.AzureAutoLogin {
ctrl.LoggerFrom(ctx).Info("Logging in to Azure ACR for " + imageRepo.Spec.Image)
authConfig, err := getAzureLoginAuth(ctx, ref)
if err != nil {
ctrl.LoggerFrom(ctx).Info("error logging into ACR " + err.Error())
imagev1.SetImageRepositoryReadiness(
imageRepo,
metav1.ConditionFalse,
meta.ReconciliationFailedReason,
err.Error(),
)
return err
}

auth := authn.FromConfig(authConfig)
options = append(options, remote.WithAuth(auth))
} else {
ctrl.LoggerFrom(ctx).Info("No image credentials secret referenced, and ACR authentication is not enabled. To enable, set the controller flag --azure-autologin-for-acr")
}
}

if imageRepo.Spec.CertSecretRef != nil {
Expand Down Expand Up @@ -591,3 +691,47 @@ func getURLHost(urlStr string) (string, error) {

return u.Host, nil
}

// getAzureLoginAuth returns authentication for ACR. The details needed for authentication
// are gotten from environment variable so there is not need to mount a host path.
func getAzureLoginAuth(ctx context.Context, ref name.Reference) (authn.AuthConfig, error) {
var authConfig authn.AuthConfig

cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
return authConfig, err
}
armToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{
Scopes: []string{string(arm.AzurePublicCloud)},
})
if err != nil {
return authConfig, err
}

ex := azure.NewExchanger(ref.Context().RegistryStr())
accessToken, err := ex.ExchangeACRAccessToken(string(armToken.Token))
if err != nil {
return authConfig, fmt.Errorf("error exchanging token: %w", err)
}

return authn.AuthConfig{
// this is the acr username used by Azure
// See documentation: https://docs.microsoft.com/en-us/azure/container-registry/container-registry-authentication?tabs=azure-cli#az-acr-login-with---expose-token
Username: "00000000-0000-0000-0000-000000000000",
Password: accessToken,
}, nil
}

// List from https://github.com/kubernetes/kubernetes/blob/v1.23.1/pkg/credentialprovider/azure/azure_credentials.go#L55
func hostIsAzureContainerRegistry(host string) bool {
for _, v := range []string{".azurecr.io", ".azurecr.cn", ".azurecr.de", ".azurecr.us"} {
if strings.HasSuffix(host, v) {
return true
}
}
return false
}

func hostIsGoogleContainerRegistry(host string) bool {
return host == "gcr.io" || strings.HasSuffix(host, ".gcr.io") || strings.HasSuffix(host, "-docker.pkg.dev")
}
21 changes: 15 additions & 6 deletions docs/spec/v1beta1/imagerepositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,18 @@ repository. This secret is expected to be in the same format as for

For a publicly accessible image repository, you will not need to provide a `secretRef`.

#### ECR and EKS
#### Automatic Authentication

When running in [<abbr title="Elastic Kubernetes Service">EKS</abbr>][EKS] and using [<abbr
title="Elastic Container Registry">ECR</abbr>][ECR] to store images, you should be able to rely on
the controller retrieving credentials automatically. The controller must be run with the flag
`--aws-autologin-for-ecr` set for this to work. The advice under "Other platforms" below will also
work for ECR.
When running on any of the three major cloud providers and using their container registry to store images,
you should be able to rely on the controller retrieving credentials automatically. The controllers must be run
with the corresponding flag for each provider.

For [<abbr title="Elastic Kubernetes Service">EKS</abbr>][EKS] and [<abbr title="Elastic Container Registry">ECR</abbr>][ECR],
the flag is `--aws-autologin-for-ecr`.
For [<abbr title="Google Kubernetes Engine">GKE</abbr>][GKE] and [<abbr title="Google Container Registry">GCR</abbr>][GCR],
the flag is `--gcp-autologin-for-gcr`.
For [<abbr title="Azure Kubernetes Service">AKS</abbr>][AKS] and [<abbr title="Azure Container Registry">ACR</abbr>][ACR],
the flag is `--azure-autologin-for-acr`.

#### Other platforms

Expand Down Expand Up @@ -261,3 +266,7 @@ and reference it under `secretRef`.
[sops-guide]: https://toolkit.fluxcd.io/guides/mozilla-sops/
[EKS]: https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html
[ECR]: https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html
[GKE]: https://cloud.google.com/kubernetes-engine/docs/concepts/kubernetes-engine-overview
[GCR]: https://cloud.google.com/container-registry/docs/overview
[AKS]: https://docs.microsoft.com/en-us/azure/aks/intro-kubernetes
[ACR]: https://docs.microsoft.com/en-us/azure/container-registry/container-registry-intro
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.17
replace github.com/fluxcd/image-reflector-controller/api => ./api

require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.12.0
github.com/Masterminds/semver/v3 v3.1.1
github.com/aws/aws-sdk-go v1.42.9
github.com/dgraph-io/badger/v3 v3.2103.2
Expand All @@ -23,6 +25,7 @@ require (
)

require (
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1 // indirect
cloud.google.com/go v0.97.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
Expand Down Expand Up @@ -61,6 +64,7 @@ require (
github.com/nxadm/tail v1.4.8 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
Expand All @@ -72,6 +76,7 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
Expand Down
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible h1:KnPIugL51v3N3WwvaSmZbxukD1WuWXOiE9fRdu32f2I=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0 h1:KQgdWmEOmaJKxaUUZwHAYh12t+b+ZJf8q3friycK1kA=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.20.0/go.mod h1:ZPW/Z0kLCTdDZaDbYTetxc9Cxl/2lNqxYHYNOF2bti0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.12.0 h1:VBvHGLJbaY0+c66NZHdS9cgjHVYSH6DDa0XJMyrblsI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.12.0/go.mod h1:GJzjM4SR9T0KyX5gKCVyz1ytD8FeWeUPCwtFCt1AyfE=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1 h1:BUYIbDf/mMZ8945v3QkG3OuqGVyS4Iek0AOLwdRAYoc=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.1/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
Expand Down Expand Up @@ -289,6 +296,7 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/docker/cli v20.10.10+incompatible h1:kcbwdgWbrBOH8QwQzaJmyriHwF7XIl4HT1qh0HTRys4=
github.com/docker/cli v20.10.10+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
Expand Down Expand Up @@ -627,6 +635,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
Expand Down Expand Up @@ -690,6 +699,9 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -905,8 +917,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -982,6 +997,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
Expand All @@ -995,6 +1011,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
Expand Down Expand Up @@ -1120,6 +1137,7 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
Loading

0 comments on commit 4ca33b4

Please sign in to comment.