зеркало из https://github.com/Azure/ARO-RP.git
Merge branch 'master' into f/guardrails-3.15.1
This commit is contained in:
Коммит
fc564970f7
|
@ -15,7 +15,7 @@ jobs:
|
|||
ci-from-docker:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.10
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.12-5
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
@ -32,7 +32,7 @@ jobs:
|
|||
vendor-check:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.10
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.12-5
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
@ -44,7 +44,7 @@ jobs:
|
|||
generate-check:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.10
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.12-5
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
|
|
@ -22,7 +22,7 @@ pr:
|
|||
resources:
|
||||
containers:
|
||||
- container: golang
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.10
|
||||
image: registry.access.redhat.com/ubi8/go-toolset:1.20.12-5
|
||||
options: --user=0
|
||||
- container: python
|
||||
image: registry.access.redhat.com/ubi8/python-39:latest
|
||||
|
|
|
@ -14,7 +14,7 @@ pr: none
|
|||
variables:
|
||||
Cdp_Definition_Build_Count: $[counter('', 0)] # needed for onebranch.pipeline.version task https://aka.ms/obpipelines/versioning
|
||||
ONEBRANCH_AME_ACR_LOGIN: cdpxb8e9ef87cd634085ab141c637806568c00.azurecr.io
|
||||
LinuxContainerImage: $(ONEBRANCH_AME_ACR_LOGIN)/b8e9ef87-cd63-4085-ab14-1c637806568c/official/ubi8/go-toolset:1.20.10 # Docker image which is used to build the project https://aka.ms/obpipelines/containers
|
||||
LinuxContainerImage: $(ONEBRANCH_AME_ACR_LOGIN)/b8e9ef87-cd63-4085-ab14-1c637806568c/official/ubi8/go-toolset:1.20.12-5 # Docker image which is used to build the project https://aka.ms/obpipelines/containers
|
||||
Debian_Frontend: noninteractive
|
||||
|
||||
resources:
|
||||
|
|
|
@ -14,7 +14,7 @@ pr: none
|
|||
variables:
|
||||
Cdp_Definition_Build_Count: $[counter('', 0)] # needed for onebranch.pipeline.version task https://aka.ms/obpipelines/versioning
|
||||
ONEBRANCH_AME_ACR_LOGIN: cdpxb8e9ef87cd634085ab141c637806568c00.azurecr.io
|
||||
LinuxContainerImage: $(ONEBRANCH_AME_ACR_LOGIN)/b8e9ef87-cd63-4085-ab14-1c637806568c/official/ubi8/go-toolset:1.20.10 # Docker image which is used to build the project https://aka.ms/obpipelines/containers
|
||||
LinuxContainerImage: $(ONEBRANCH_AME_ACR_LOGIN)/b8e9ef87-cd63-4085-ab14-1c637806568c/official/ubi8/go-toolset:1.20.12-5 # Docker image which is used to build the project https://aka.ms/obpipelines/containers
|
||||
Debian_Frontend: noninteractive
|
||||
|
||||
resources:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Uses a multi-stage container build to build the RP & E2E components.
|
||||
#
|
||||
ARG REGISTRY
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.10 AS builder
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.12-5 AS builder
|
||||
|
||||
USER root
|
||||
ENV GOPATH=/root/go
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Uses a multi-stage container build to build the RP.
|
||||
#
|
||||
ARG REGISTRY
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.10 AS builder
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.12-5 AS builder
|
||||
|
||||
USER root
|
||||
ENV GOPATH=/root/go
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
ARG REGISTRY
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.10-1 AS builder
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.12-5 AS builder
|
||||
ARG GATEKEEPER_VERSION
|
||||
ENV DOWNLOAD_URL=https://github.com/open-policy-agent/gatekeeper/archive/${GATEKEEPER_VERSION}.tar.gz
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Uses a multi-stage container build to build the proxy
|
||||
#
|
||||
ARG REGISTRY
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.10 AS builder
|
||||
FROM ${REGISTRY}/ubi8/go-toolset:1.20.12-5 AS builder
|
||||
USER root
|
||||
ENV GOPATH=/root/go
|
||||
RUN mkdir -p /app
|
||||
|
|
5
Makefile
5
Makefile
|
@ -9,7 +9,7 @@ NO_CACHE ?= true
|
|||
export GOFLAGS=$(GO_FLAGS)
|
||||
|
||||
# fluentbit version must also be updated in RP code, see pkg/util/version/const.go
|
||||
MARINER_VERSION = 20230321
|
||||
MARINER_VERSION = 20240301
|
||||
FLUENTBIT_VERSION = 1.9.10
|
||||
FLUENTBIT_IMAGE ?= ${RP_IMAGE_ACR}.azurecr.io/fluentbit:$(FLUENTBIT_VERSION)-cm$(MARINER_VERSION)
|
||||
AUTOREST_VERSION = 3.6.3
|
||||
|
@ -114,7 +114,8 @@ generate-kiota:
|
|||
go run ./hack/licenses -dirs ./pkg/util/graph/graphsdk
|
||||
|
||||
init-contrib:
|
||||
cp -R hack/git/hooks/* .git/hooks/
|
||||
install -v hack/git/hooks/* .git/hooks/
|
||||
|
||||
|
||||
image-aro-multistage:
|
||||
docker build --platform=linux/amd64 --network=host --no-cache -f Dockerfile.aro-multistage -t $(ARO_IMAGE) --build-arg REGISTRY=$(REGISTRY) .
|
||||
|
|
|
@ -9,24 +9,10 @@
|
|||
1. Build the development `az aro` extension:
|
||||
|
||||
```bash
|
||||
. ./env
|
||||
make az
|
||||
```
|
||||
|
||||
1. Verify that the ARO extension path is in your `az` configuration:
|
||||
|
||||
```bash
|
||||
grep -q 'dev_sources' ~/.azure/config || cat >>~/.azure/config <<EOF
|
||||
[extension]
|
||||
dev_sources = $PWD/python
|
||||
EOF
|
||||
```
|
||||
|
||||
> Alternatively, if you do not want to configure the Azure CLI to utilize
|
||||
> this extension globally, you can set the `AZURE_EXTENSION_DEV_SOURCES`
|
||||
> environment variable to the `./python/` subfolder of this repository, e.g.
|
||||
> in your ./env environment file, when you want to use the extension, and
|
||||
> unset it when you do not.
|
||||
|
||||
1. Verify the ARO extension is registered:
|
||||
|
||||
```bash
|
||||
|
@ -41,7 +27,10 @@
|
|||
```
|
||||
|
||||
Note: you will be able to update your development `az aro` extension in the
|
||||
future by simply running `git pull`.
|
||||
future by simply running `git pull`. If you need to use the "prod" extension,
|
||||
what is bundled in `az` natively rather than your `./python`, you can
|
||||
`unset AZURE_EXTENSION_DEV_SOURCES` (found in your `./env` file).
|
||||
|
||||
|
||||
|
||||
## Prepare your environment
|
||||
|
|
|
@ -267,7 +267,7 @@
|
|||
--nsg-name rp-nsg \
|
||||
--access Allow \
|
||||
--priority 500 \
|
||||
--source-address-prefixes "$(curl --silent ipecho.net/plain)/32" \
|
||||
--source-address-prefixes "$(curl --silent -4 ipecho.net/plain)/32" \
|
||||
--protocol Tcp \
|
||||
--destination-port-ranges 22
|
||||
```
|
||||
|
@ -290,7 +290,7 @@
|
|||
--nsg-name gateway-nsg \
|
||||
--access Allow \
|
||||
--priority 500 \
|
||||
--source-address-prefixes "$(curl --silent ipecho.net/plain)/32" \
|
||||
--source-address-prefixes "$(curl --silent -4 ipecho.net/plain)/32" \
|
||||
--protocol Tcp \
|
||||
--destination-port-ranges 22
|
||||
```
|
||||
|
@ -315,7 +315,7 @@
|
|||
--nsg-name rp-nsg \
|
||||
--access Allow \
|
||||
--priority 499 \
|
||||
--source-address-prefixes "$(curl --silent ipecho.net/plain)/32" \
|
||||
--source-address-prefixes "$(curl --silent -4 ipecho.net/plain)/32" \
|
||||
--protocol Tcp \
|
||||
--destination-port-ranges 443
|
||||
```
|
||||
|
|
|
@ -20,10 +20,6 @@ Subscription feature flags used by ARO-RP include:
|
|||
graduating features to production such that they only apply on our Red Hat
|
||||
engineering subscription.
|
||||
|
||||
* Microsoft.RedHatOpenShift/SaveAROTestConfig: used on our test subscriptions to
|
||||
cause the pkg/billing to copy billing data to a storage account so that it can
|
||||
be validated by the billing E2E tests.
|
||||
|
||||
Subscription feature flags are also used for API preview, INT and region
|
||||
rollout. See the RP ARM manifest for more details.
|
||||
|
||||
|
|
|
@ -139,8 +139,10 @@ Make sure that `PKG_CONFIG_PATH` contains the pkgconfig files of the above packa
|
|||
cd ${GOPATH:-$HOME/go}/src/github.com/Azure/ARO-RP
|
||||
```
|
||||
|
||||
1. Add standard git hooks
|
||||
1. Configure local git
|
||||
|
||||
```bash
|
||||
make init-contrib
|
||||
git config --global github.user <<user_name>>
|
||||
```
|
||||
|
||||
|
|
|
@ -5,5 +5,6 @@ export RESOURCEGROUP=$USER-aro-$LOCATION
|
|||
export DATABASE_ACCOUNT_NAME=$USER-aro-$LOCATION
|
||||
export DATABASE_NAME=ARO
|
||||
export KEYVAULT_PREFIX=$USER-aro-$LOCATION
|
||||
export KEYVAULT_PREFIX=${KEYVAULT_PREFIX::20}
|
||||
export ARO_IMAGE=${USER}aro.azurecr.io/aro:$(git rev-parse --short=7 HEAD)$([[ $(git status --porcelain) = "" ]] || echo -dirty)
|
||||
export FLUENTBIT_IMAGE=${USER}aro.azurecr.io/fluentbit:latest
|
||||
export FLUENTBIT_IMAGE=${USER}aro.azurecr.io/fluentbit:latest
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export LOCATION=eastus
|
||||
export ARO_IMAGE=arointsvc.azurecr.io/aro:latest
|
||||
export NO_CACHE=false
|
||||
export AZURE_EXTENSION_DEV_SOURCES="$(pwd)/python"
|
||||
|
||||
. secrets/env
|
||||
|
|
3
go.mod
3
go.mod
|
@ -5,8 +5,9 @@ go 1.20
|
|||
require (
|
||||
github.com/Azure/azure-sdk-for-go v63.1.0+incompatible
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v2 v2.5.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.4.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1
|
||||
github.com/Azure/go-autorest/autorest v0.11.29
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.23
|
||||
|
|
7
go.sum
7
go.sum
|
@ -5,13 +5,16 @@ github.com/Azure/azure-sdk-for-go v63.1.0+incompatible h1:yNC7qlSUWVF8p0TzxdmWW1
|
|||
github.com/Azure/azure-sdk-for-go v63.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v2 v2.5.0 h1:FTNvxTFH/08JBmhcbL5lmLaGYVXokZM6Ni92Mqr+gSg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v2 v2.5.0/go.mod h1:T0ryqIz5h5qg4HOBni+VeRn24alSqOx1Se1IAwUByOk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.4.0 h1:HlZMUZW8S4P9oob1nCHxCCKrytxyLc+24nUJGssoEto=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.4.0/go.mod h1:StGsLbuJh06Bd8IBfnAlIFV3fLb+gkczONWf15hpX2E=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU=
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package admin
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetList represents a List of role sets.
|
||||
type PlatformWorkloadIdentityRoleSetList struct {
|
||||
// The list of role sets.
|
||||
PlatformWorkloadIdentityRoleSets []*PlatformWorkloadIdentityRoleSet `json:"value"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSet represents a mapping from the names of OCP operators to the built-in roles that should be assigned to those operator's corresponding managed identities for a particular OCP version.
|
||||
type PlatformWorkloadIdentityRoleSet struct {
|
||||
// The ID for the resource.
|
||||
ID string `json:"id,omitempty" mutable:"case"`
|
||||
|
||||
// Name of the resource.
|
||||
Name string `json:"name,omitempty" mutable:"case"`
|
||||
|
||||
// The properties for the PlatformWorkloadIdentityRoleSet resource.
|
||||
Properties PlatformWorkloadIdentityRoleSetProperties `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetProperties represents the properties of a PlatformWorkloadIdentityRoleSet resource.
|
||||
type PlatformWorkloadIdentityRoleSetProperties struct {
|
||||
// OpenShiftVersion represents the version associated with this set of roles.
|
||||
OpenShiftVersion string `json:"openShiftVersion,omitempty"`
|
||||
|
||||
// PlatformWorkloadIdentityRoles represents the set of roles associated with this version.
|
||||
PlatformWorkloadIdentityRoles []PlatformWorkloadIdentityRole `json:"platformWorkloadIdentityRoles,omitempty" mutable:"true"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRole represents a mapping from a particular OCP operator to the built-in role that should be assigned to that operator's corresponding managed identity.
|
||||
type PlatformWorkloadIdentityRole struct {
|
||||
// OperatorName represents the name of the operator that this role is for.
|
||||
OperatorName string `json:"operatorName,omitempty" mutable:"true"`
|
||||
|
||||
// RoleDefinitionName represents the name of the role.
|
||||
RoleDefinitionName string `json:"roleDefinitionName,omitempty" mutable:"true"`
|
||||
|
||||
// RoleDefinitionID represents the resource ID of the role definition.
|
||||
RoleDefinitionID string `json:"roleDefinitionId,omitempty" mutable:"true"`
|
||||
|
||||
// ServiceAccounts represents the set of service accounts associated with the given operator, since each service account needs its own federated credential.
|
||||
ServiceAccounts []string `json:"serviceAccounts,omitempty" mutable:"true"`
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package admin
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
/*
|
||||
TODO: Uncomment once API endpoints have been implemented and this code is being used.
|
||||
|
||||
type platformWorkloadIdentityRoleSetConverter struct{}
|
||||
|
||||
// platformWorkloadIdentityRoleSetConverter.ToExternal returns a new external representation
|
||||
// of the internal object, reading from the subset of the internal object's
|
||||
// fields that appear in the external representation. ToExternal does not
|
||||
// modify its argument; there is no pointer aliasing between the passed and
|
||||
// returned objects.
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToExternal(s *api.PlatformWorkloadIdentityRoleSet) interface{} {
|
||||
out := &PlatformWorkloadIdentityRoleSet{
|
||||
Properties: PlatformWorkloadIdentityRoleSetProperties{
|
||||
OpenShiftVersion: s.Properties.OpenShiftVersion,
|
||||
PlatformWorkloadIdentityRoles: make([]PlatformWorkloadIdentityRole, 0, len(s.Properties.PlatformWorkloadIdentityRoles)),
|
||||
},
|
||||
}
|
||||
|
||||
for i, r := range s.Properties.PlatformWorkloadIdentityRoles {
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = make([]string, 0, len(r.ServiceAccounts))
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = append(out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts, r.ServiceAccounts...)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// ToExternalList returns a slice of external representations of the internal
|
||||
// objects
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToExternalList(sets []*api.PlatformWorkloadIdentityRoleSet) interface{} {
|
||||
l := &PlatformWorkloadIdentityRoleSetList{
|
||||
PlatformWorkloadIdentityRoleSets: make([]*PlatformWorkloadIdentityRoleSet, 0, len(sets)),
|
||||
}
|
||||
|
||||
for _, set := range sets {
|
||||
l.PlatformWorkloadIdentityRoleSets = append(l.PlatformWorkloadIdentityRoleSets, c.ToExternal(set).(*PlatformWorkloadIdentityRoleSet))
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// ToInternal overwrites in place a pre-existing internal object, setting (only)
|
||||
// all mapped fields from the external representation. ToInternal modifies its
|
||||
// argument; there is no pointer aliasing between the passed and returned
|
||||
// objects
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToInternal(_new interface{}, out *api.PlatformWorkloadIdentityRoleSet) {
|
||||
new := _new.(*PlatformWorkloadIdentityRoleSet)
|
||||
|
||||
out.Properties.OpenShiftVersion = new.Properties.OpenShiftVersion
|
||||
out.Properties.PlatformWorkloadIdentityRoles = make([]api.PlatformWorkloadIdentityRole, 0, len(new.Properties.PlatformWorkloadIdentityRoles))
|
||||
|
||||
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = make([]string, 0, len(r.ServiceAccounts))
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts = append(out.Properties.PlatformWorkloadIdentityRoles[i].ServiceAccounts, r.ServiceAccounts...)
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,71 @@
|
|||
package admin
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
/*
|
||||
TODO: Uncomment once API endpoints have been implemented and this code is being used.
|
||||
|
||||
type platformWorkloadIdentityRoleSetStaticValidator struct{}
|
||||
|
||||
func (sv platformWorkloadIdentityRoleSetStaticValidator) Static(_new interface{}, _current *api.PlatformWorkloadIdentityRoleSet) error {
|
||||
new := _new.(*PlatformWorkloadIdentityRoleSet)
|
||||
|
||||
var current *PlatformWorkloadIdentityRoleSet
|
||||
if _current != nil {
|
||||
current = (&platformWorkloadIdentityRoleSetConverter{}).ToExternal(_current).(*PlatformWorkloadIdentityRoleSet)
|
||||
}
|
||||
|
||||
err := sv.validate(new, current == nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if current == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return sv.validateDelta(new, current)
|
||||
}
|
||||
|
||||
func (sv platformWorkloadIdentityRoleSetStaticValidator) validate(new *PlatformWorkloadIdentityRoleSet, isCreate bool) error {
|
||||
if new.Properties.OpenShiftVersion == "" {
|
||||
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "properties.openShiftVersion", "Must be provided")
|
||||
}
|
||||
|
||||
if new.Properties.PlatformWorkloadIdentityRoles == nil || len(new.Properties.PlatformWorkloadIdentityRoles) == 0 {
|
||||
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, "properties.platformWorkloadIdentityRoles", "Must be provided and must be non-empty")
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
|
||||
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
|
||||
if r.OperatorName == "" {
|
||||
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].operatorName", i), "Must be provided"))
|
||||
}
|
||||
|
||||
if r.RoleDefinitionName == "" {
|
||||
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionName", i), "Must be provided"))
|
||||
}
|
||||
|
||||
if r.RoleDefinitionID == "" {
|
||||
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].roleDefinitionId", i), "Must be provided"))
|
||||
}
|
||||
|
||||
if r.ServiceAccounts == nil || len(r.ServiceAccounts) == 0 {
|
||||
errs = append(errs, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidParameter, fmt.Sprintf("properties.platformWorkloadIdentityRoles[%d].serviceAccounts", i), "Must be provided and must be non-empty"))
|
||||
}
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (sv platformWorkloadIdentityRoleSetStaticValidator) validateDelta(new, current *PlatformWorkloadIdentityRoleSet) error {
|
||||
err := immutable.Validate("", new, current)
|
||||
if err != nil {
|
||||
err := err.(*immutable.ValidationError)
|
||||
return api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodePropertyChangeNotAllowed, err.Target, err.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
|
@ -4,11 +4,6 @@ package api
|
|||
// Licensed under the Apache License 2.0.
|
||||
|
||||
const (
|
||||
// FeatureFlagSaveAROTestConfig is the feature in the subscription that is used
|
||||
// to indicate if we need to save ARO cluster config into the E2E
|
||||
// StorageAccount
|
||||
FeatureFlagSaveAROTestConfig = "Microsoft.RedHatOpenShift/SaveAROTestConfig"
|
||||
|
||||
// FeatureFlagMTU3900 is the feature in the subscription that causes new
|
||||
// OpenShift cluster nodes to use the largest available Maximum Transmission
|
||||
// Unit (MTU) on Azure virtual networks, which as of late 2021 is 3900 bytes.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package api
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
// PlatformWorkloadIdentityRoleSet represents a mapping from the names of OCP operators to the built-in roles that should be assigned to those operator's corresponding managed identities for a particular OCP version.
|
||||
type PlatformWorkloadIdentityRoleSet struct {
|
||||
MissingFields
|
||||
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Deleting bool `json:"deleting,omitempty"` // https://docs.microsoft.com/en-us/azure/cosmos-db/change-feed-design-patterns#deletes
|
||||
|
||||
Properties PlatformWorkloadIdentityRoleSetProperties `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetProperties represents the properties of a PlatformWorkloadIdentityRoleSet resource.
|
||||
type PlatformWorkloadIdentityRoleSetProperties struct {
|
||||
OpenShiftVersion string `json:"openShiftVersion,omitempty"`
|
||||
PlatformWorkloadIdentityRoles []PlatformWorkloadIdentityRole `json:"platformWorkloadIdentityRoles,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRole represents a mapping from a particular OCP operator to the built-in role that should be assigned to that operator's corresponding managed identity.
|
||||
type PlatformWorkloadIdentityRole struct {
|
||||
OperatorName string `json:"operatorName,omitempty"`
|
||||
RoleDefinitionName string `json:"roleDefinitionName,omitempty"`
|
||||
RoleDefinitionID string `json:"roleDefinitionId,omitempty"`
|
||||
ServiceAccounts []string `json:"serviceAccounts,omitempty"`
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package api
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetDocuments represents a set of PlatformWorkloadIdentityRoleSetDocuments.
|
||||
// pkg/database/cosmosdb requires its definition.
|
||||
type PlatformWorkloadIdentityRoleSetDocuments struct {
|
||||
Count int `json:"_count,omitempty"`
|
||||
ResourceID string `json:"_rid,omitempty"`
|
||||
PlatformWorkloadIdentityRoleSetDocuments []*PlatformWorkloadIdentityRoleSetDocument `json:"Documents,omitempty"`
|
||||
}
|
||||
|
||||
func (c *PlatformWorkloadIdentityRoleSetDocuments) String() string {
|
||||
return encodeJSON(c)
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetDocument represents a document specifying a mapping from the names of OCP operators to the built-in roles that should be assigned to those operator's corresponding managed identities for a particular OCP version.
|
||||
// pkg/database/cosmosdb requires its definition.
|
||||
type PlatformWorkloadIdentityRoleSetDocument struct {
|
||||
MissingFields
|
||||
|
||||
ID string `json:"id,omitempty"`
|
||||
ResourceID string `json:"_rid,omitempty"`
|
||||
Timestamp int `json:"_ts,omitempty"`
|
||||
Self string `json:"_self,omitempty"`
|
||||
ETag string `json:"_etag,omitempty" deep:"-"`
|
||||
Attachments string `json:"_attachments,omitempty"`
|
||||
TTL int `json:"ttl,omitempty"`
|
||||
LSN int `json:"_lsn,omitempty"`
|
||||
Metadata map[string]interface{} `json:"_metadata,omitempty"`
|
||||
|
||||
PlatformWorkloadIdentityRoleSet *PlatformWorkloadIdentityRoleSet `json:"platformWorkloadIdentityRoleSet,omitempty"`
|
||||
}
|
||||
|
||||
func (c *PlatformWorkloadIdentityRoleSetDocument) String() string {
|
||||
return encodeJSON(c)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package api
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
func ExamplePlatformWorkloadIdentityRoleSetDocument() *PlatformWorkloadIdentityRoleSetDocument {
|
||||
return &PlatformWorkloadIdentityRoleSetDocument{
|
||||
MissingFields: MissingFields{},
|
||||
ID: "00000000-0000-0000-0000-000000000000",
|
||||
PlatformWorkloadIdentityRoleSet: &PlatformWorkloadIdentityRoleSet{
|
||||
ID: "00000000-0000-0000-0000-000000000000",
|
||||
Name: "4.14",
|
||||
Type: "Microsoft.RedHatOpenShift/PlatformWorkloadIdentityRoleSet",
|
||||
Properties: PlatformWorkloadIdentityRoleSetProperties{
|
||||
OpenShiftVersion: "4.14",
|
||||
PlatformWorkloadIdentityRoles: []PlatformWorkloadIdentityRole{
|
||||
{
|
||||
OperatorName: "ServiceOperator",
|
||||
RoleDefinitionName: "AzureRedHatOpenShiftServiceOperator",
|
||||
RoleDefinitionID: "/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-0000-0000-000000000000",
|
||||
ServiceAccounts: []string{
|
||||
"aro-operator-master",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -15,13 +15,7 @@ import (
|
|||
var secretPreservingJSONHandle *codec.JsonHandle
|
||||
|
||||
func init() {
|
||||
secretPreservingJSONHandle = &codec.JsonHandle{
|
||||
BasicHandle: codec.BasicHandle{
|
||||
DecodeOptions: codec.DecodeOptions{
|
||||
ErrorIfNoField: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
secretPreservingJSONHandle = &codec.JsonHandle{}
|
||||
|
||||
err := secretPreservingJSONHandle.SetInterfaceExt(reflect.TypeOf(SecureBytes{}), 1, secureHidingExt{})
|
||||
if err != nil {
|
||||
|
|
|
@ -277,4 +277,11 @@ func (c openShiftClusterConverter) ExternalNoReadOnly(_oc interface{}) {
|
|||
if oc.Properties.NetworkProfile.LoadBalancerProfile != nil {
|
||||
oc.Properties.NetworkProfile.LoadBalancerProfile.EffectiveOutboundIPs = nil
|
||||
}
|
||||
oc.SystemData = nil
|
||||
oc.Properties.ConsoleProfile.URL = ""
|
||||
oc.Properties.APIServerProfile.URL = ""
|
||||
oc.Properties.APIServerProfile.IP = ""
|
||||
for i := range oc.Properties.IngressProfiles {
|
||||
oc.Properties.IngressProfiles[i].IP = ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,4 +326,15 @@ func (c openShiftClusterConverter) ExternalNoReadOnly(_oc interface{}) {
|
|||
if oc.Properties.NetworkProfile.LoadBalancerProfile != nil {
|
||||
oc.Properties.NetworkProfile.LoadBalancerProfile.EffectiveOutboundIPs = nil
|
||||
}
|
||||
oc.SystemData = nil
|
||||
oc.Properties.ConsoleProfile.URL = ""
|
||||
oc.Properties.APIServerProfile.URL = ""
|
||||
oc.Properties.APIServerProfile.IP = ""
|
||||
for i := range oc.Properties.IngressProfiles {
|
||||
oc.Properties.IngressProfiles[i].IP = ""
|
||||
}
|
||||
for i := range oc.Properties.PlatformWorkloadIdentityProfile.PlatformWorkloadIdentities {
|
||||
oc.Properties.PlatformWorkloadIdentityProfile.PlatformWorkloadIdentities[i].ClientID = ""
|
||||
oc.Properties.PlatformWorkloadIdentityProfile.PlatformWorkloadIdentities[i].ObjectID = ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package v20240812preview
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetList represents a List of role sets.
|
||||
type PlatformWorkloadIdentityRoleSetList struct {
|
||||
// The list of role sets.
|
||||
PlatformWorkloadIdentityRoleSets []*PlatformWorkloadIdentityRoleSet `json:"value"`
|
||||
|
||||
// Next Link to next operation.
|
||||
NextLink string `json:"nextLink,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSet represents a mapping from the names of OCP operators to the built-in roles that should be assigned to those operator's corresponding managed identities for a particular OCP version.
|
||||
type PlatformWorkloadIdentityRoleSet struct {
|
||||
proxyResource bool
|
||||
|
||||
// The ID for the resource.
|
||||
ID string `json:"id,omitempty" mutable:"case"`
|
||||
|
||||
// Name of the resource.
|
||||
Name string `json:"name,omitempty" mutable:"case"`
|
||||
|
||||
// The resource type.
|
||||
Type string `json:"type,omitempty" mutable:"case"`
|
||||
|
||||
// The properties for the PlatformWorkloadIdentityRoleSet resource.
|
||||
Properties PlatformWorkloadIdentityRoleSetProperties `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRoleSetProperties represents the properties of a PlatformWorkloadIdentityRoleSet resource.
|
||||
type PlatformWorkloadIdentityRoleSetProperties struct {
|
||||
// OpenShiftVersion represents the version associated with this set of roles.
|
||||
OpenShiftVersion string `json:"openShiftVersion,omitempty"`
|
||||
|
||||
// PlatformWorkloadIdentityRoles represents the set of roles associated with this version.
|
||||
PlatformWorkloadIdentityRoles []PlatformWorkloadIdentityRole `json:"platformWorkloadIdentityRoles,omitempty"`
|
||||
}
|
||||
|
||||
// PlatformWorkloadIdentityRole represents a mapping from a particular OCP operator to the built-in role that should be assigned to that operator's corresponding managed identity.
|
||||
type PlatformWorkloadIdentityRole struct {
|
||||
// OperatorName represents the name of the operator that this role is for.
|
||||
OperatorName string `json:"operatorName,omitempty"`
|
||||
|
||||
// RoleDefinitionName represents the name of the role.
|
||||
RoleDefinitionName string `json:"roleDefinitionName,omitempty"`
|
||||
|
||||
// RoleDefinitionID represents the resource ID of the role definition.
|
||||
RoleDefinitionID string `json:"roleDefinitionId,omitempty"`
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package v20240812preview
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
)
|
||||
|
||||
type platformWorkloadIdentityRoleSetConverter struct{}
|
||||
|
||||
// platformWorkloadIdentityRoleSetConverter.ToExternal returns a new external representation
|
||||
// of the internal object, reading from the subset of the internal object's
|
||||
// fields that appear in the external representation. ToExternal does not
|
||||
// modify its argument; there is no pointer aliasing between the passed and
|
||||
// returned objects.
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToExternal(s *api.PlatformWorkloadIdentityRoleSet) interface{} {
|
||||
out := &PlatformWorkloadIdentityRoleSet{
|
||||
ID: s.ID,
|
||||
proxyResource: true,
|
||||
Properties: PlatformWorkloadIdentityRoleSetProperties{
|
||||
OpenShiftVersion: s.Properties.OpenShiftVersion,
|
||||
PlatformWorkloadIdentityRoles: make([]PlatformWorkloadIdentityRole, 0, len(s.Properties.PlatformWorkloadIdentityRoles)),
|
||||
},
|
||||
}
|
||||
|
||||
for i, r := range s.Properties.PlatformWorkloadIdentityRoles {
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// ToExternalList returns a slice of external representations of the internal
|
||||
// objects
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToExternalList(sets []*api.PlatformWorkloadIdentityRoleSet) interface{} {
|
||||
l := &PlatformWorkloadIdentityRoleSetList{
|
||||
PlatformWorkloadIdentityRoleSets: make([]*PlatformWorkloadIdentityRoleSet, 0, len(sets)),
|
||||
}
|
||||
|
||||
for _, set := range sets {
|
||||
l.PlatformWorkloadIdentityRoleSets = append(l.PlatformWorkloadIdentityRoleSets, c.ToExternal(set).(*PlatformWorkloadIdentityRoleSet))
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// ToInternal overwrites in place a pre-existing internal object, setting (only)
|
||||
// all mapped fields from the external representation. ToInternal modifies its
|
||||
// argument; there is no pointer aliasing between the passed and returned
|
||||
// objects
|
||||
func (c platformWorkloadIdentityRoleSetConverter) ToInternal(_new interface{}, out *api.PlatformWorkloadIdentityRoleSet) {
|
||||
new := _new.(*PlatformWorkloadIdentityRoleSet)
|
||||
|
||||
out.Properties.OpenShiftVersion = new.Properties.OpenShiftVersion
|
||||
out.Properties.PlatformWorkloadIdentityRoles = make([]api.PlatformWorkloadIdentityRole, 0, len(new.Properties.PlatformWorkloadIdentityRoles))
|
||||
|
||||
for i, r := range new.Properties.PlatformWorkloadIdentityRoles {
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].OperatorName = r.OperatorName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionName = r.RoleDefinitionName
|
||||
out.Properties.PlatformWorkloadIdentityRoles[i].RoleDefinitionID = r.RoleDefinitionID
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package v20240812preview
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import "github.com/Azure/ARO-RP/pkg/api"
|
||||
|
||||
func examplePlatformWorkloadIdentityRoleSet() *PlatformWorkloadIdentityRoleSet {
|
||||
doc := api.ExamplePlatformWorkloadIdentityRoleSetDocument()
|
||||
ext := (&platformWorkloadIdentityRoleSetConverter{}).ToExternal(doc.PlatformWorkloadIdentityRoleSet)
|
||||
return ext.(*PlatformWorkloadIdentityRoleSet)
|
||||
}
|
||||
|
||||
func ExamplePlatformWorkloadIdentityRoleSetResponse() interface{} {
|
||||
return examplePlatformWorkloadIdentityRoleSet()
|
||||
}
|
||||
|
||||
func ExamplePlatformWorkloadIdentityRoleSetListResponse() interface{} {
|
||||
return &PlatformWorkloadIdentityRoleSetList{
|
||||
PlatformWorkloadIdentityRoleSets: []*PlatformWorkloadIdentityRoleSet{
|
||||
ExamplePlatformWorkloadIdentityRoleSetResponse().(*PlatformWorkloadIdentityRoleSet),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ import (
|
|||
testlog "github.com/Azure/ARO-RP/test/util/log"
|
||||
)
|
||||
|
||||
const TEST_PULLSPEC = "registry.access.redhat.com/ubi8/go-toolset:1.20.10"
|
||||
const TEST_PULLSPEC = "registry.access.redhat.com/ubi8/go-toolset:1.20.12-5"
|
||||
|
||||
var _ = Describe("Podman", Ordered, func() {
|
||||
var err error
|
||||
|
|
|
@ -78,13 +78,7 @@ func getDatabaseKey(keys sdkcosmos.DatabaseAccountsClientListKeysResponse, log *
|
|||
}
|
||||
|
||||
func NewJSONHandle(aead encryption.AEAD) (*codec.JsonHandle, error) {
|
||||
h := &codec.JsonHandle{
|
||||
BasicHandle: codec.BasicHandle{
|
||||
DecodeOptions: codec.DecodeOptions{
|
||||
ErrorIfNoField: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
h := &codec.JsonHandle{}
|
||||
|
||||
if aead == nil {
|
||||
return h, nil
|
||||
|
|
|
@ -11,160 +11,167 @@
|
|||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'))]",
|
||||
"properties": {
|
||||
"resource": {
|
||||
"id": "[parameters('databaseName')]"
|
||||
},
|
||||
"options": {
|
||||
"autoscaleSettings": {
|
||||
"maxThroughput": 1000
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
"id": "[parameters('databaseName')]"
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'))]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15"
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/AsyncOperations')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"defaultTtl": 604800,
|
||||
"id": "AsyncOperations",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": 604800
|
||||
},
|
||||
"options": {}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/AsyncOperations')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/OpenShiftVersions')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"defaultTtl": -1,
|
||||
"id": "OpenShiftVersions",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": -1
|
||||
},
|
||||
"options": {}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/OpenShiftVersions')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/ClusterManagerConfigurations')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"id": "ClusterManagerConfigurations",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/partitionKey"
|
||||
],
|
||||
"kind": "Hash"
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/ClusterManagerConfigurations')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Billing')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"id": "Billing",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Billing')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Gateway')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"defaultTtl": -1,
|
||||
"id": "Gateway",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": -1
|
||||
},
|
||||
"options": {}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Gateway')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Monitors')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"defaultTtl": -1,
|
||||
"id": "Monitors",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": -1
|
||||
},
|
||||
"options": {}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Monitors')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/OpenShiftClusters')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"id": "OpenShiftClusters",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/partitionKey"
|
||||
],
|
||||
"kind": "Hash"
|
||||
]
|
||||
},
|
||||
"uniqueKeyPolicy": {
|
||||
"uniqueKeys": [
|
||||
|
@ -185,59 +192,52 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/OpenShiftClusters')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Portal')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"defaultTtl": -1,
|
||||
"id": "Portal",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
},
|
||||
"defaultTtl": -1
|
||||
},
|
||||
"options": {}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Portal')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
],
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Subscriptions')]",
|
||||
"properties": {
|
||||
"options": {},
|
||||
"resource": {
|
||||
"id": "Subscriptions",
|
||||
"partitionKey": {
|
||||
"kind": "Hash",
|
||||
"paths": [
|
||||
"/id"
|
||||
],
|
||||
"kind": "Hash"
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
},
|
||||
"name": "[concat(parameters('databaseAccountName'), '/', parameters('databaseName'), '/Subscriptions')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers",
|
||||
"location": "[resourceGroup().location]",
|
||||
"apiVersion": "2021-01-15",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('databaseName'))]"
|
||||
]
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@
|
|||
},
|
||||
"properties": {
|
||||
"upgradePolicy": {
|
||||
"mode": "Manual"
|
||||
"mode": "Rolling"
|
||||
},
|
||||
"virtualMachineProfile": {
|
||||
"osProfile": {
|
||||
|
@ -296,7 +296,7 @@
|
|||
"autoUpgradeMinorVersion": true,
|
||||
"settings": {},
|
||||
"protectedSettings": {
|
||||
"script": "[base64(concat(base64ToString('c2V0IC1leAoK'),'PROXYIMAGE=$(base64 -d \u003c\u003c\u003c''',base64(parameters('proxyImage')),''')\n','PROXYIMAGEAUTH=$(base64 -d \u003c\u003c\u003c''',base64(parameters('proxyImageAuth')),''')\n','PROXYCERT=''',parameters('proxyCert'),'''\n','PROXYCLIENTCERT=''',parameters('proxyClientCert'),'''\n','PROXYKEY=''',parameters('proxyKey'),'''\n','\n',base64ToString('I0FkZGluZyByZXRyeSBsb2dpYyB0byB5dW0gY29tbWFuZHMgaW4gb3JkZXIgdG8gYXZvaWQgc3RhbGxpbmcgb3V0IG9uIHJlc291cmNlIGxvY2tzCmVjaG8gInJ1bm5pbmcgUkhVSSBmaXgiCmZvciBhdHRlbXB0IGluIHsxLi41fTsgZG8KICB5dW0gdXBkYXRlIC15IC0tZGlzYWJsZXJlcG89JyonIC0tZW5hYmxlcmVwbz0ncmh1aS1taWNyb3NvZnQtYXp1cmUqJyAmJiBicmVhawogIGlmIFtbICR7YXR0ZW1wdH0gLWx0IDUgXV07IHRoZW4gc2xlZXAgMTA7IGVsc2UgZXhpdCAxOyBmaQpkb25lCgplY2hvICJydW5uaW5nIHl1bSB1cGRhdGUiCmZvciBhdHRlbXB0IGluIHsxLi41fTsgZG8KICB5dW0gLXkgLXggV0FMaW51eEFnZW50IC14IFdBTGludXhBZ2VudC11ZGV2IHVwZGF0ZSAtLWFsbG93ZXJhc2luZyAmJiBicmVhawogIGlmIFtbICR7YXR0ZW1wdH0gLWx0IDUgXV07IHRoZW4gc2xlZXAgMTA7IGVsc2UgZXhpdCAxOyBmaQpkb25lCgplY2hvICJpbnN0YWxsaW5nIHBvZG1hbi1kb2NrZXIiCmZvciBhdHRlbXB0IGluIHsxLi41fTsgZG8KICB5dW0gLXkgaW5zdGFsbCBwb2RtYW4tZG9ja2VyICYmIGJyZWFrCiAgaWYgW1sgJHthdHRlbXB0fSAtbHQgNSBdXTsgdGhlbiBzbGVlcCAxMDsgZWxzZSBleGl0IDE7IGZpCmRvbmUKCmZpcmV3YWxsLWNtZCAtLWFkZC1wb3J0PTQ0My90Y3AgLS1wZXJtYW5lbnQKCm1rZGlyIC9yb290Ly5kb2NrZXIKY2F0ID4vcm9vdC8uZG9ja2VyL2NvbmZpZy5qc29uIDw8RU9GCnsKCSJhdXRocyI6IHsKCQkiJHtQUk9YWUlNQUdFJSUvKn0iOiB7CgkJCSJhdXRoIjogIiRQUk9YWUlNQUdFQVVUSCIKCQl9Cgl9Cn0KRU9GCgpta2RpciAtcCAvZXRjL2NvbnRhaW5lcnMvCnRvdWNoIC9ldGMvY29udGFpbmVycy9ub2RvY2tlcgoKZG9ja2VyIHB1bGwgIiRQUk9YWUlNQUdFIgoKbWtkaXIgL2V0Yy9wcm94eQpiYXNlNjQgLWQgPDw8IiRQUk9YWUNFUlQiID4vZXRjL3Byb3h5L3Byb3h5LmNydApiYXNlNjQgLWQgPDw8IiRQUk9YWUtFWSIgPi9ldGMvcHJveHkvcHJveHkua2V5CmJhc2U2NCAtZCA8PDwiJFBST1hZQ0xJRU5UQ0VSVCIgPi9ldGMvcHJveHkvcHJveHktY2xpZW50LmNydApjaG93biAtUiAxMDAwOjEwMDAgL2V0Yy9wcm94eQpjaG1vZCAwNjAwIC9ldGMvcHJveHkvcHJveHkua2V5CgpjYXQgPi9ldGMvc3lzY29uZmlnL3Byb3h5IDw8RU9GClBST1hZX0lNQUdFPSckUFJPWFlJTUFHRScKRU9GCgpjYXQgPi9ldGMvc3lzdGVtZC9zeXN0ZW0vcHJveHkuc2VydmljZSA8PCdFT0YnCltVbml0XQpBZnRlcj1uZXR3b3JrLW9ubGluZS50YXJnZXQKV2FudHM9bmV0d29yay1vbmxpbmUudGFyZ2V0CgpbU2VydmljZV0KRW52aXJvbm1lbnRGaWxlPS9ldGMvc3lzY29uZmlnL3Byb3h5CkV4ZWNTdGFydFByZT0tL3Vzci9iaW4vZG9ja2VyIHJtIC1mICVuCkV4ZWNTdGFydD0vdXNyL2Jpbi9kb2NrZXIgcnVuIC0tcm0gLS1uYW1lICVuIC1wIDQ0Mzo4NDQzIC12IC9ldGMvcHJveHk6L3NlY3JldHMgJFBST1hZX0lNQUdFCkV4ZWNTdG9wPS91c3IvYmluL2RvY2tlciBzdG9wICVuClJlc3RhcnQ9YWx3YXlzClJlc3RhcnRTZWM9MQpTdGFydExpbWl0SW50ZXJ2YWw9MAoKW0luc3RhbGxdCldhbnRlZEJ5PW11bHRpLXVzZXIudGFyZ2V0CkVPRgoKc3lzdGVtY3RsIGVuYWJsZSBwcm94eS5zZXJ2aWNlCgpjYXQgPi9ldGMvY3Jvbi53ZWVrbHkvcHVsbC1pbWFnZSA8PCdFT0YnCiMhL2Jpbi9iYXNoCgpkb2NrZXIgcHVsbCAkUFJPWFlJTUFHRQpzeXN0ZW1jdGwgcmVzdGFydCBwcm94eS5zZXJ2aWNlCkVPRgpjaG1vZCAreCAvZXRjL2Nyb24ud2Vla2x5L3B1bGwtaW1hZ2UKCmNhdCA+L2V0Yy9jcm9uLndlZWtseS95dW11cGRhdGUgPDwnRU9GJwojIS9iaW4vYmFzaAoKeXVtIHVwZGF0ZSAteQpFT0YKY2htb2QgK3ggL2V0Yy9jcm9uLndlZWtseS95dW11cGRhdGUKCmNhdCA+L2V0Yy9jcm9uLmRhaWx5L3Jlc3RhcnQtcHJveHkgPDwnRU9GJwojIS9iaW4vYmFzaAoKc3lzdGVtY3RsIHJlc3RhcnQgcHJveHkuc2VydmljZQpFT0YKY2htb2QgK3ggL2V0Yy9jcm9uLmRhaWx5L3Jlc3RhcnQtcHJveHkKCigKCXNsZWVwIDMwCglyZWJvb3QKKSAmCg==')))]"
|
||||
"script": "[base64(concat(base64ToString('c2V0IC1leAoK'),'PROXYIMAGE=$(base64 -d \u003c\u003c\u003c''',base64(parameters('proxyImage')),''')\n','PROXYIMAGEAUTH=$(base64 -d \u003c\u003c\u003c''',base64(parameters('proxyImageAuth')),''')\n','PROXYCERT=''',parameters('proxyCert'),'''\n','PROXYCLIENTCERT=''',parameters('proxyClientCert'),'''\n','PROXYKEY=''',parameters('proxyKey'),'''\n','\n',base64ToString('I0FkZGluZyByZXRyeSBsb2dpYyB0byB5dW0gY29tbWFuZHMgaW4gb3JkZXIgdG8gYXZvaWQgc3RhbGxpbmcgb3V0IG9uIHJlc291cmNlIGxvY2tzCmVjaG8gInJ1bm5pbmcgUkhVSSBmaXgiCmZvciBhdHRlbXB0IGluIHsxLi42MH07IGRvCiAgeXVtIHVwZGF0ZSAteSAtLWRpc2FibGVyZXBvPScqJyAtLWVuYWJsZXJlcG89J3JodWktbWljcm9zb2Z0LWF6dXJlKicgJiYgYnJlYWsKICBpZiBbWyAke2F0dGVtcHR9IC1sdCA2MCBdXTsgdGhlbiBzbGVlcCAzMDsgZWxzZSBleGl0IDE7IGZpCmRvbmUKCmVjaG8gInJ1bm5pbmcgeXVtIHVwZGF0ZSIKZm9yIGF0dGVtcHQgaW4gezEuLjYwfTsgZG8KICB5dW0gLXkgLXggV0FMaW51eEFnZW50IC14IFdBTGludXhBZ2VudC11ZGV2IHVwZGF0ZSAtLWFsbG93ZXJhc2luZyAmJiBicmVhawogIGlmIFtbICR7YXR0ZW1wdH0gLWx0IDYwIF1dOyB0aGVuIHNsZWVwIDMwOyBlbHNlIGV4aXQgMTsgZmkKZG9uZQoKZWNobyAiaW5zdGFsbGluZyBwb2RtYW4tZG9ja2VyIgpmb3IgYXR0ZW1wdCBpbiB7MS4uNjB9OyBkbwogIHl1bSAteSBpbnN0YWxsIHBvZG1hbi1kb2NrZXIgJiYgYnJlYWsKICBpZiBbWyAke2F0dGVtcHR9IC1sdCA2MCBdXTsgdGhlbiBzbGVlcCAzMDsgZWxzZSBleGl0IDE7IGZpCmRvbmUKCmZpcmV3YWxsLWNtZCAtLWFkZC1wb3J0PTQ0My90Y3AgLS1wZXJtYW5lbnQKCm1rZGlyIC9yb290Ly5kb2NrZXIKY2F0ID4vcm9vdC8uZG9ja2VyL2NvbmZpZy5qc29uIDw8RU9GCnsKCSJhdXRocyI6IHsKCQkiJHtQUk9YWUlNQUdFJSUvKn0iOiB7CgkJCSJhdXRoIjogIiRQUk9YWUlNQUdFQVVUSCIKCQl9Cgl9Cn0KRU9GCgpta2RpciAtcCAvZXRjL2NvbnRhaW5lcnMvCnRvdWNoIC9ldGMvY29udGFpbmVycy9ub2RvY2tlcgoKZG9ja2VyIHB1bGwgIiRQUk9YWUlNQUdFIgoKbWtkaXIgL2V0Yy9wcm94eQpiYXNlNjQgLWQgPDw8IiRQUk9YWUNFUlQiID4vZXRjL3Byb3h5L3Byb3h5LmNydApiYXNlNjQgLWQgPDw8IiRQUk9YWUtFWSIgPi9ldGMvcHJveHkvcHJveHkua2V5CmJhc2U2NCAtZCA8PDwiJFBST1hZQ0xJRU5UQ0VSVCIgPi9ldGMvcHJveHkvcHJveHktY2xpZW50LmNydApjaG93biAtUiAxMDAwOjEwMDAgL2V0Yy9wcm94eQpjaG1vZCAwNjAwIC9ldGMvcHJveHkvcHJveHkua2V5CgpjYXQgPi9ldGMvc3lzY29uZmlnL3Byb3h5IDw8RU9GClBST1hZX0lNQUdFPSckUFJPWFlJTUFHRScKRU9GCgpjYXQgPi9ldGMvc3lzdGVtZC9zeXN0ZW0vcHJveHkuc2VydmljZSA8PCdFT0YnCltVbml0XQpBZnRlcj1uZXR3b3JrLW9ubGluZS50YXJnZXQKV2FudHM9bmV0d29yay1vbmxpbmUudGFyZ2V0CgpbU2VydmljZV0KRW52aXJvbm1lbnRGaWxlPS9ldGMvc3lzY29uZmlnL3Byb3h5CkV4ZWNTdGFydFByZT0tL3Vzci9iaW4vZG9ja2VyIHJtIC1mICVuCkV4ZWNTdGFydD0vdXNyL2Jpbi9kb2NrZXIgcnVuIC0tcm0gLS1uYW1lICVuIC1wIDQ0Mzo4NDQzIC12IC9ldGMvcHJveHk6L3NlY3JldHMgJFBST1hZX0lNQUdFCkV4ZWNTdG9wPS91c3IvYmluL2RvY2tlciBzdG9wICVuClJlc3RhcnQ9YWx3YXlzClJlc3RhcnRTZWM9MQpTdGFydExpbWl0SW50ZXJ2YWw9MAoKW0luc3RhbGxdCldhbnRlZEJ5PW11bHRpLXVzZXIudGFyZ2V0CkVPRgoKc3lzdGVtY3RsIGVuYWJsZSBwcm94eS5zZXJ2aWNlCgpjYXQgPi9ldGMvY3Jvbi53ZWVrbHkvcHVsbC1pbWFnZSA8PCdFT0YnCiMhL2Jpbi9iYXNoCgpkb2NrZXIgcHVsbCAkUFJPWFlJTUFHRQpzeXN0ZW1jdGwgcmVzdGFydCBwcm94eS5zZXJ2aWNlCkVPRgpjaG1vZCAreCAvZXRjL2Nyb24ud2Vla2x5L3B1bGwtaW1hZ2UKCmNhdCA+L2V0Yy9jcm9uLndlZWtseS95dW11cGRhdGUgPDwnRU9GJwojIS9iaW4vYmFzaAoKeXVtIHVwZGF0ZSAteQpFT0YKY2htb2QgK3ggL2V0Yy9jcm9uLndlZWtseS95dW11cGRhdGUKCmNhdCA+L2V0Yy9jcm9uLmRhaWx5L3Jlc3RhcnQtcHJveHkgPDwnRU9GJwojIS9iaW4vYmFzaAoKc3lzdGVtY3RsIHJlc3RhcnQgcHJveHkuc2VydmljZQpFT0YKY2htb2QgK3ggL2V0Yy9jcm9uLmRhaWx5L3Jlc3RhcnQtcHJveHkKCigKCXNsZWVwIDMwCglyZWJvb3QKKSAmCg==')))]"
|
||||
},
|
||||
"provisionAfterExtensions": [
|
||||
"Microsoft.Azure.Monitor.AzureMonitorLinuxAgent",
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -26,7 +26,8 @@
|
|||
{
|
||||
"actions": [
|
||||
"Microsoft.Resources/subscriptions/resourceGroups/read",
|
||||
"Microsoft.Resources/subscriptions/resourceGroups/write"
|
||||
"Microsoft.Resources/subscriptions/resourceGroups/write",
|
||||
"Microsoft.Authorization/*/action"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -54,32 +54,33 @@
|
|||
"location": "[resourceGroup().location]"
|
||||
},
|
||||
{
|
||||
"apiVersion": "2023-04-15",
|
||||
"kind": "GlobalDocumentDB",
|
||||
"location": "[resourceGroup().location]",
|
||||
"name": "[parameters('databaseAccountName')]",
|
||||
"properties": {
|
||||
"consistencyPolicy": {
|
||||
"defaultConsistencyLevel": "Strong"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"locationName": "[resourceGroup().location]"
|
||||
}
|
||||
],
|
||||
"databaseAccountOfferType": "Standard",
|
||||
"backupPolicy": {
|
||||
"periodicModeProperties": {
|
||||
"backupIntervalInMinutes": 240,
|
||||
"backupRetentionIntervalInHours": 720
|
||||
},
|
||||
"type": "Periodic"
|
||||
}
|
||||
},
|
||||
"consistencyPolicy": {
|
||||
"defaultConsistencyLevel": "Strong"
|
||||
},
|
||||
"databaseAccountOfferType": "Standard",
|
||||
"locations": [
|
||||
{
|
||||
"locationName": "[resourceGroup().location]"
|
||||
}
|
||||
],
|
||||
"minimalTlsVersion": "Tls12"
|
||||
},
|
||||
"name": "[parameters('databaseAccountName')]",
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts",
|
||||
"location": "[resourceGroup().location]",
|
||||
"tags": {
|
||||
"defaultExperience": "Core (SQL)"
|
||||
},
|
||||
"apiVersion": "2021-01-15"
|
||||
"type": "Microsoft.DocumentDB/databaseAccounts"
|
||||
},
|
||||
{
|
||||
"name": "[guid(resourceGroup().id, parameters('rpServicePrincipalId'), 'RP / Reader')]",
|
||||
|
|
|
@ -29,12 +29,6 @@
|
|||
"azureSecPackVSATenantId": {
|
||||
"value": ""
|
||||
},
|
||||
"billingE2EStorageAccountId": {
|
||||
"value": ""
|
||||
},
|
||||
"billingServicePrincipalId": {
|
||||
"value": ""
|
||||
},
|
||||
"clusterDefaultInstallerPullspec": {
|
||||
"value": ""
|
||||
},
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -48,8 +48,6 @@ type Configuration struct {
|
|||
ARMAPICABundle *string `json:"armApiCaBundle,omitempty"`
|
||||
ARMAPIClientCertCommonName *string `json:"armApiClientCertCommonName,omitempty"`
|
||||
ARMClientID *string `json:"armClientId,omitempty"`
|
||||
BillingE2EStorageAccountID *string `json:"billingE2EStorageAccountId,omitempty"`
|
||||
BillingServicePrincipalID *string `json:"billingServicePrincipalId,omitempty"`
|
||||
ClusterMDMAccount *string `json:"clusterMdmAccount,omitempty" value:"required"`
|
||||
ClusterMDSDAccount *string `json:"clusterMdsdAccount,omitempty" value:"required"`
|
||||
ClusterMDSDConfigVersion *string `json:"clusterMdsdConfigVersion,omitempty" value:"required"`
|
||||
|
|
|
@ -53,7 +53,7 @@ func (g *generator) devProxyVMSS() *arm.Resource {
|
|||
},
|
||||
VirtualMachineScaleSetProperties: &mgmtcompute.VirtualMachineScaleSetProperties{
|
||||
UpgradePolicy: &mgmtcompute.UpgradePolicy{
|
||||
Mode: mgmtcompute.UpgradeModeManual,
|
||||
Mode: mgmtcompute.UpgradeModeRolling,
|
||||
},
|
||||
VirtualMachineProfile: &mgmtcompute.VirtualMachineScaleSetVMProfile{
|
||||
OsProfile: &mgmtcompute.VirtualMachineScaleSetOSProfile{
|
||||
|
|
|
@ -259,7 +259,7 @@ func (g *generator) gatewayVMSS() *arm.Resource {
|
|||
Tags: map[string]*string{},
|
||||
VirtualMachineScaleSetProperties: &mgmtcompute.VirtualMachineScaleSetProperties{
|
||||
UpgradePolicy: &mgmtcompute.UpgradePolicy{
|
||||
Mode: mgmtcompute.UpgradeModeManual,
|
||||
Mode: mgmtcompute.UpgradeModeRolling,
|
||||
},
|
||||
VirtualMachineProfile: &mgmtcompute.VirtualMachineScaleSetVMProfile{
|
||||
OsProfile: &mgmtcompute.VirtualMachineScaleSetOSProfile{
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdkcosmos "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v2"
|
||||
mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
|
||||
mgmtdocumentdb "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2021-01-15/documentdb"
|
||||
mgmtkeyvault "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2019-09-01/keyvault"
|
||||
mgmtmsi "github.com/Azure/azure-sdk-for-go/services/msi/mgmt/2018-11-30/msi"
|
||||
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
|
||||
|
@ -457,7 +457,6 @@ func (g *generator) rpVMSS() *arm.Resource {
|
|||
"azureCloudName",
|
||||
"azureSecPackQualysUrl",
|
||||
"azureSecPackVSATenantId",
|
||||
"billingE2EStorageAccountId",
|
||||
"clusterMdmAccount",
|
||||
"clusterMdsdAccount",
|
||||
"clusterMdsdConfigVersion",
|
||||
|
@ -548,7 +547,7 @@ func (g *generator) rpVMSS() *arm.Resource {
|
|||
Tags: map[string]*string{},
|
||||
VirtualMachineScaleSetProperties: &mgmtcompute.VirtualMachineScaleSetProperties{
|
||||
UpgradePolicy: &mgmtcompute.UpgradePolicy{
|
||||
Mode: mgmtcompute.UpgradeModeManual,
|
||||
Mode: mgmtcompute.UpgradeModeRolling,
|
||||
},
|
||||
VirtualMachineProfile: &mgmtcompute.VirtualMachineScaleSetVMProfile{
|
||||
OsProfile: &mgmtcompute.VirtualMachineScaleSetOSProfile{
|
||||
|
@ -978,25 +977,31 @@ func (g *generator) rpServiceKeyvault() *arm.Resource {
|
|||
}
|
||||
|
||||
func (g *generator) rpCosmosDB() []*arm.Resource {
|
||||
cosmosdb := &mgmtdocumentdb.DatabaseAccountCreateUpdateParameters{
|
||||
Kind: mgmtdocumentdb.GlobalDocumentDB,
|
||||
DatabaseAccountCreateUpdateProperties: &mgmtdocumentdb.DatabaseAccountCreateUpdateProperties{
|
||||
ConsistencyPolicy: &mgmtdocumentdb.ConsistencyPolicy{
|
||||
DefaultConsistencyLevel: mgmtdocumentdb.Strong,
|
||||
dbType := sdkcosmos.DatabaseAccountKindGlobalDocumentDB
|
||||
consistency := sdkcosmos.DefaultConsistencyLevelStrong
|
||||
backupPolicy := sdkcosmos.BackupPolicyTypePeriodic
|
||||
minTLSVersion := sdkcosmos.MinimalTLSVersionTls12
|
||||
|
||||
cosmosdb := &sdkcosmos.DatabaseAccountCreateUpdateParameters{
|
||||
Kind: &dbType,
|
||||
Properties: &sdkcosmos.DatabaseAccountCreateUpdateProperties{
|
||||
ConsistencyPolicy: &sdkcosmos.ConsistencyPolicy{
|
||||
DefaultConsistencyLevel: &consistency,
|
||||
},
|
||||
Locations: &[]mgmtdocumentdb.Location{
|
||||
Locations: []*sdkcosmos.Location{
|
||||
{
|
||||
LocationName: to.StringPtr("[resourceGroup().location]"),
|
||||
},
|
||||
},
|
||||
DatabaseAccountOfferType: to.StringPtr(string(mgmtdocumentdb.Standard)),
|
||||
BackupPolicy: mgmtdocumentdb.PeriodicModeBackupPolicy{
|
||||
Type: mgmtdocumentdb.TypePeriodic,
|
||||
PeriodicModeProperties: &mgmtdocumentdb.PeriodicModeProperties{
|
||||
DatabaseAccountOfferType: to.StringPtr("Standard"),
|
||||
BackupPolicy: &sdkcosmos.PeriodicModeBackupPolicy{
|
||||
Type: &backupPolicy,
|
||||
PeriodicModeProperties: &sdkcosmos.PeriodicModeProperties{
|
||||
BackupIntervalInMinutes: to.Int32Ptr(240), //4 hours
|
||||
BackupRetentionIntervalInHours: to.Int32Ptr(720), //30 days
|
||||
},
|
||||
},
|
||||
MinimalTLSVersion: &minTLSVersion,
|
||||
},
|
||||
Name: to.StringPtr("[parameters('databaseAccountName')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts"),
|
||||
|
@ -1009,12 +1014,13 @@ func (g *generator) rpCosmosDB() []*arm.Resource {
|
|||
r := &arm.Resource{
|
||||
Resource: cosmosdb,
|
||||
APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts",
|
||||
}
|
||||
if g.production {
|
||||
cosmosdb.IPRules = &[]mgmtdocumentdb.IPAddressOrRange{}
|
||||
cosmosdb.IsVirtualNetworkFilterEnabled = to.BoolPtr(true)
|
||||
cosmosdb.VirtualNetworkRules = &[]mgmtdocumentdb.VirtualNetworkRule{}
|
||||
cosmosdb.DisableKeyBasedMetadataWriteAccess = to.BoolPtr(true)
|
||||
cosmosdb.Properties.IPRules = []*sdkcosmos.IPAddressOrRange{}
|
||||
cosmosdb.Properties.IsVirtualNetworkFilterEnabled = to.BoolPtr(true)
|
||||
cosmosdb.Properties.VirtualNetworkRules = []*sdkcosmos.VirtualNetworkRule{}
|
||||
cosmosdb.Properties.DisableKeyBasedMetadataWriteAccess = to.BoolPtr(true)
|
||||
}
|
||||
|
||||
rs := []*arm.Resource{
|
||||
|
@ -1031,12 +1037,12 @@ func (g *generator) rpCosmosDB() []*arm.Resource {
|
|||
|
||||
func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Resource {
|
||||
database := &arm.Resource{
|
||||
Resource: &mgmtdocumentdb.SQLDatabaseCreateUpdateParameters{
|
||||
SQLDatabaseCreateUpdateProperties: &mgmtdocumentdb.SQLDatabaseCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLDatabaseResource{
|
||||
Resource: &sdkcosmos.SQLDatabaseCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLDatabaseCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLDatabaseResource{
|
||||
ID: to.StringPtr("[" + databaseName + "]"),
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{
|
||||
Options: &sdkcosmos.CreateUpdateOptions{
|
||||
Throughput: to.Int32Ptr(cosmosDbStandardProvisionedThroughputHack),
|
||||
},
|
||||
},
|
||||
|
@ -1045,21 +1051,23 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
Location: to.StringPtr("[resourceGroup().location]"),
|
||||
},
|
||||
APIVersion: azureclient.APIVersion("Microsoft.DocumentDB"),
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
}
|
||||
hashPartitionKey := sdkcosmos.PartitionKindHash
|
||||
portal := &arm.Resource{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("Portal"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
DefaultTTL: to.Int32Ptr(-1),
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{
|
||||
Options: &sdkcosmos.CreateUpdateOptions{
|
||||
Throughput: to.Int32Ptr(cosmosDbPortalProvisionedThroughputHack),
|
||||
},
|
||||
},
|
||||
|
@ -1071,22 +1079,23 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
}
|
||||
|
||||
gateway := &arm.Resource{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("Gateway"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
DefaultTTL: to.Int32Ptr(-1),
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{
|
||||
Options: &sdkcosmos.CreateUpdateOptions{
|
||||
Throughput: to.Int32Ptr(cosmosDbGatewayProvisionedThroughputHack),
|
||||
},
|
||||
},
|
||||
|
@ -1098,34 +1107,35 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
}
|
||||
|
||||
if !g.production {
|
||||
database.Resource.(*mgmtdocumentdb.SQLDatabaseCreateUpdateParameters).SQLDatabaseCreateUpdateProperties.Options = &mgmtdocumentdb.CreateUpdateOptions{
|
||||
AutoscaleSettings: &mgmtdocumentdb.AutoscaleSettings{
|
||||
database.Resource.(*sdkcosmos.SQLDatabaseCreateUpdateParameters).Properties.Options = &sdkcosmos.CreateUpdateOptions{
|
||||
AutoscaleSettings: &sdkcosmos.AutoscaleSettings{
|
||||
MaxThroughput: to.Int32Ptr(1000),
|
||||
},
|
||||
}
|
||||
portal.Resource.(*mgmtdocumentdb.SQLContainerCreateUpdateParameters).SQLContainerCreateUpdateProperties.Options = &mgmtdocumentdb.CreateUpdateOptions{}
|
||||
gateway.Resource.(*mgmtdocumentdb.SQLContainerCreateUpdateParameters).SQLContainerCreateUpdateProperties.Options = &mgmtdocumentdb.CreateUpdateOptions{}
|
||||
portal.Resource.(*sdkcosmos.SQLContainerCreateUpdateParameters).Properties.Options = &sdkcosmos.CreateUpdateOptions{}
|
||||
gateway.Resource.(*sdkcosmos.SQLContainerCreateUpdateParameters).Properties.Options = &sdkcosmos.CreateUpdateOptions{}
|
||||
}
|
||||
|
||||
rs := []*arm.Resource{
|
||||
database,
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("AsyncOperations"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
DefaultTTL: to.Int32Ptr(7 * 86400), // 7 days
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/AsyncOperations')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1135,21 +1145,22 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("OpenShiftVersions"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
DefaultTTL: to.Int32Ptr(-1),
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/OpenShiftVersions')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1159,20 +1170,21 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("ClusterManagerConfigurations"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/partitionKey",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/partitionKey"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/ClusterManagerConfigurations')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1182,20 +1194,21 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("Billing"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/Billing')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1205,22 +1218,23 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
gateway,
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("Monitors"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
DefaultTTL: to.Int32Ptr(-1),
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/Monitors')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1230,39 +1244,40 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("OpenShiftClusters"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/partitionKey",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/partitionKey"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
UniqueKeyPolicy: &mgmtdocumentdb.UniqueKeyPolicy{
|
||||
UniqueKeys: &[]mgmtdocumentdb.UniqueKey{
|
||||
UniqueKeyPolicy: &sdkcosmos.UniqueKeyPolicy{
|
||||
UniqueKeys: []*sdkcosmos.UniqueKey{
|
||||
{
|
||||
Paths: &[]string{
|
||||
"/key",
|
||||
Paths: []*string{
|
||||
to.StringPtr("/key"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Paths: &[]string{
|
||||
"/clusterResourceGroupIdKey",
|
||||
Paths: []*string{
|
||||
to.StringPtr("/clusterResourceGroupIdKey"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Paths: &[]string{
|
||||
"/clientIdKey",
|
||||
Paths: []*string{
|
||||
to.StringPtr("/clientIdKey"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/OpenShiftClusters')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1272,21 +1287,22 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
portal,
|
||||
{
|
||||
Resource: &mgmtdocumentdb.SQLContainerCreateUpdateParameters{
|
||||
SQLContainerCreateUpdateProperties: &mgmtdocumentdb.SQLContainerCreateUpdateProperties{
|
||||
Resource: &mgmtdocumentdb.SQLContainerResource{
|
||||
Resource: &sdkcosmos.SQLContainerCreateUpdateParameters{
|
||||
Properties: &sdkcosmos.SQLContainerCreateUpdateProperties{
|
||||
Resource: &sdkcosmos.SQLContainerResource{
|
||||
ID: to.StringPtr("Subscriptions"),
|
||||
PartitionKey: &mgmtdocumentdb.ContainerPartitionKey{
|
||||
Paths: &[]string{
|
||||
"/id",
|
||||
PartitionKey: &sdkcosmos.ContainerPartitionKey{
|
||||
Paths: []*string{
|
||||
to.StringPtr("/id"),
|
||||
},
|
||||
Kind: mgmtdocumentdb.PartitionKindHash,
|
||||
Kind: &hashPartitionKey,
|
||||
},
|
||||
},
|
||||
Options: &mgmtdocumentdb.CreateUpdateOptions{},
|
||||
Options: &sdkcosmos.CreateUpdateOptions{},
|
||||
},
|
||||
Name: to.StringPtr("[concat(parameters('databaseAccountName'), '/', " + databaseName + ", '/Subscriptions')]"),
|
||||
Type: to.StringPtr("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers"),
|
||||
|
@ -1296,6 +1312,7 @@ func (g *generator) database(databaseName string, addDependsOn bool) []*arm.Reso
|
|||
DependsOn: []string{
|
||||
"[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), " + databaseName + ")]",
|
||||
},
|
||||
Type: "Microsoft.DocumentDB/databaseAccounts/sqlDatabases",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1426,19 +1443,6 @@ func (g *generator) rpRBAC() []*arm.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func (g *generator) rpBillingContributorRbac() []*arm.Resource {
|
||||
return []*arm.Resource{
|
||||
rbac.ResourceRoleAssignmentWithName(
|
||||
rbac.RoleDocumentDBAccountContributor,
|
||||
"parameters('billingServicePrincipalId')",
|
||||
"Microsoft.DocumentDB/databaseAccounts",
|
||||
"parameters('databaseAccountName')",
|
||||
"concat(parameters('databaseAccountName'), '/Microsoft.Authorization/', guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('billingServicePrincipalId') , 'Billing / DocumentDB Account Contributor'))",
|
||||
"[greater(length(parameters('billingServicePrincipalId')), 0)]",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *generator) rpACR() *arm.Resource {
|
||||
return &arm.Resource{
|
||||
Resource: &mgmtcontainerregistry.Registry{
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#Adding retry logic to yum commands in order to avoid stalling out on resource locks
|
||||
echo "running RHUI fix"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum update -y --disablerepo='*' --enablerepo='rhui-microsoft-azure*' && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "running yum update"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y -x WALinuxAgent -x WALinuxAgent-udev update --allowerasing && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "installing podman-docker"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y install podman-docker && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
firewall-cmd --add-port=443/tcp --permanent
|
||||
|
|
|
@ -7,15 +7,15 @@ systemctl reload sshd.service
|
|||
|
||||
#Adding retry logic to yum commands in order to avoid stalling out on resource locks
|
||||
echo "running RHUI fix"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum update -y --disablerepo='*' --enablerepo='rhui-microsoft-azure*' && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "running yum update"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y -x WALinuxAgent -x WALinuxAgent-udev update --allowerasing && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "extending partition table"
|
||||
|
@ -34,9 +34,9 @@ xfs_growfs /var
|
|||
rpm --import https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8
|
||||
rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
||||
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "configuring logrotate"
|
||||
|
@ -111,10 +111,10 @@ EOF
|
|||
semanage fcontext -a -t var_log_t "/var/log/journal(/.*)?"
|
||||
mkdir -p /var/log/journal
|
||||
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y install clamav azsec-clamav azsec-monitor azure-cli azure-mdsd azure-security podman-docker openssl-perl python3 && break
|
||||
# hack - we are installing python3 on hosts due to an issue with Azure Linux Extensions https://github.com/Azure/azure-linux-extensions/pull/1505
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "applying firewall rules"
|
||||
|
|
|
@ -7,15 +7,15 @@ systemctl reload sshd.service
|
|||
|
||||
#Adding retry logic to yum commands in order to avoid stalling out on resource locks
|
||||
echo "running RHUI fix"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum update -y --disablerepo='*' --enablerepo='rhui-microsoft-azure*' && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "running yum update"
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y -x WALinuxAgent -x WALinuxAgent-udev update --allowerasing && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "extending partition table"
|
||||
|
@ -35,9 +35,9 @@ echo "importing rpm repositories"
|
|||
rpm --import https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8
|
||||
rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
||||
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && break
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
echo "configuring logrotate"
|
||||
|
@ -95,10 +95,10 @@ EOF
|
|||
semanage fcontext -a -t var_log_t "/var/log/journal(/.*)?"
|
||||
mkdir -p /var/log/journal
|
||||
|
||||
for attempt in {1..5}; do
|
||||
for attempt in {1..60}; do
|
||||
yum -y install clamav azsec-clamav azsec-monitor azure-cli azure-mdsd azure-security podman podman-docker openssl-perl python3 && break
|
||||
# hack - we are installing python3 on hosts due to an issue with Azure Linux Extensions https://github.com/Azure/azure-linux-extensions/pull/1505
|
||||
if [[ ${attempt} -lt 5 ]]; then sleep 10; else exit 1; fi
|
||||
if [[ ${attempt} -lt 60 ]]; then sleep 30; else exit 1; fi
|
||||
done
|
||||
|
||||
# https://access.redhat.com/security/cve/cve-2020-13401
|
||||
|
@ -272,7 +272,6 @@ ARM_API_CLIENT_CERT_COMMON_NAME='$ARMAPICLIENTCERTCOMMONNAME'
|
|||
AZURE_ARM_CLIENT_ID='$ARMCLIENTID'
|
||||
AZURE_FP_CLIENT_ID='$FPCLIENTID'
|
||||
AZURE_FP_SERVICE_PRINCIPAL_ID='$FPSERVICEPRINCIPALID'
|
||||
BILLING_E2E_STORAGE_ACCOUNT_ID='$BILLINGE2ESTORAGEACCOUNTID'
|
||||
CLUSTER_MDM_ACCOUNT='$CLUSTERMDMACCOUNT'
|
||||
CLUSTER_MDM_NAMESPACE=RP
|
||||
CLUSTER_MDSD_ACCOUNT='$CLUSTERMDSDACCOUNT'
|
||||
|
@ -312,7 +311,6 @@ ExecStart=/usr/bin/docker run \
|
|||
-e ARM_API_CLIENT_CERT_COMMON_NAME \
|
||||
-e AZURE_ARM_CLIENT_ID \
|
||||
-e AZURE_FP_CLIENT_ID \
|
||||
-e BILLING_E2E_STORAGE_ACCOUNT_ID \
|
||||
-e CLUSTER_MDM_ACCOUNT \
|
||||
-e CLUSTER_MDM_NAMESPACE \
|
||||
-e CLUSTER_MDSD_ACCOUNT \
|
||||
|
|
|
@ -41,8 +41,6 @@ func (g *generator) rpTemplate() *arm.Template {
|
|||
"azureCloudName",
|
||||
"azureSecPackQualysUrl",
|
||||
"azureSecPackVSATenantId",
|
||||
"billingE2EStorageAccountId",
|
||||
"billingServicePrincipalId",
|
||||
"clusterMdmAccount",
|
||||
"clusterMdsdAccount",
|
||||
"clusterMdsdConfigVersion",
|
||||
|
@ -100,8 +98,6 @@ func (g *generator) rpTemplate() *arm.Template {
|
|||
case "armApiCaBundle",
|
||||
"armApiClientCertCommonName",
|
||||
"armClientId",
|
||||
"billingServicePrincipalId",
|
||||
"billingE2EStorageAccountId",
|
||||
"gatewayDomains",
|
||||
"rpFeatures":
|
||||
p.DefaultValue = ""
|
||||
|
@ -177,7 +173,6 @@ func (g *generator) rpTemplate() *arm.Template {
|
|||
g.rpLBAlert(67.0, 3, "rp-degraded-alert", "PT15M", "PT6H", "DipAvailability"), // 1/3 backend down for 1h or 2/3 down for 3h in the last 6h
|
||||
g.rpLBAlert(33.0, 2, "rp-vnet-alert", "PT5M", "PT5M", "VipAvailability")) // this will trigger only if the Azure network infrastructure between the loadBalancers and VMs is down for 3.5min
|
||||
// more on alerts https://msazure.visualstudio.com/AzureRedHatOpenShift/_wiki/wikis/ARO.wiki/53765/WIP-Alerting
|
||||
t.Resources = append(t.Resources, g.rpBillingContributorRbac()...)
|
||||
|
||||
t.Resources = append(t.Resources,
|
||||
g.virtualNetworkPeering("rp-vnet/peering-gateway-vnet", "[resourceId(parameters('gatewayResourceGroupName'), 'Microsoft.Network/virtualNetworks', 'gateway-vnet')]", false, false, nil),
|
||||
|
|
|
@ -149,9 +149,10 @@ func (f *frontend) _putOrPatchOpenShiftCluster(ctx context.Context, log *logrus.
|
|||
// Patch should be used for updating individual fields of the document.
|
||||
case http.MethodPatch:
|
||||
ext = converter.ToExternal(doc.OpenShiftCluster)
|
||||
converter.ExternalNoReadOnly(ext)
|
||||
}
|
||||
|
||||
converter.ExternalNoReadOnly(ext)
|
||||
|
||||
err = json.Unmarshal(body, &ext)
|
||||
if err != nil {
|
||||
return nil, api.NewCloudError(http.StatusBadRequest, api.CloudErrorCodeInvalidRequestContent, "", "The request content was invalid and could not be deserialized: %q.", err)
|
||||
|
|
|
@ -51,11 +51,6 @@ func (f *frontend) _putSubscription(ctx context.Context, r *http.Request) ([]byt
|
|||
oldState := doc.Subscription.State
|
||||
|
||||
h := &codec.JsonHandle{
|
||||
BasicHandle: codec.BasicHandle{
|
||||
DecodeOptions: codec.DecodeOptions{
|
||||
ErrorIfNoField: true,
|
||||
},
|
||||
},
|
||||
Indent: 4,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,47 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
sdkcosmos "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos/v2"
|
||||
gofrsuuid "github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// MarshalJSON marshals the nested r.Resource ignoring any MarshalJSON() methods
|
||||
// on its types. It then merges remaining fields of r over the result
|
||||
func (r *Resource) MarshalJSON() ([]byte, error) {
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
// hack to handle newer track2 sdk which doesn't have json tags
|
||||
if strings.HasPrefix(r.Type, "Microsoft.DocumentDB/databaseAccounts/sqlDatabases") {
|
||||
if reflect.TypeOf(r.Resource) == reflect.TypeOf(&sdkcosmos.SQLDatabaseCreateUpdateParameters{}) {
|
||||
b, err = r.Resource.(*sdkcosmos.SQLDatabaseCreateUpdateParameters).MarshalJSON()
|
||||
} else if reflect.TypeOf(r.Resource) == reflect.TypeOf(&sdkcosmos.SQLContainerCreateUpdateParameters{}) {
|
||||
b, err = r.Resource.(*sdkcosmos.SQLContainerCreateUpdateParameters).MarshalJSON()
|
||||
}
|
||||
} else if strings.HasPrefix(r.Type, "Microsoft.DocumentDB/databaseAccounts") {
|
||||
b, err = r.Resource.(*sdkcosmos.DatabaseAccountCreateUpdateParameters).MarshalJSON()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
dataMap := map[string]interface{}{}
|
||||
err = json.Unmarshal(b, &dataMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dataMap["apiVersion"] = r.APIVersion
|
||||
if r.DependsOn != nil {
|
||||
dataMap["dependsOn"] = r.DependsOn
|
||||
}
|
||||
return json.Marshal(dataMap)
|
||||
}
|
||||
|
||||
resource := reflect.ValueOf(shadowCopy(r.Resource))
|
||||
outer := reflect.ValueOf(*r)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ var apiVersions = map[string]string{
|
|||
"microsoft.compute/snapshots": "2020-05-01",
|
||||
"microsoft.containerregistry": "2020-11-01-preview",
|
||||
"microsoft.resources/deployments": "2021-04-01",
|
||||
"microsoft.documentdb": "2021-01-15",
|
||||
"microsoft.documentdb": "2023-04-15",
|
||||
"microsoft.insights": "2018-03-01",
|
||||
"microsoft.keyvault": "2019-09-01",
|
||||
"microsoft.keyvault/vaults/accesspolicies": "2021-10-01",
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package armkeyvault
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/azcore"
|
||||
)
|
||||
|
||||
type VaultsClient interface {
|
||||
CheckNameAvailability(ctx context.Context, vaultName armkeyvault.VaultCheckNameAvailabilityParameters, options *armkeyvault.VaultsClientCheckNameAvailabilityOptions) (armkeyvault.VaultsClientCheckNameAvailabilityResponse, error)
|
||||
}
|
||||
|
||||
type vaultsClient struct {
|
||||
*armkeyvault.VaultsClient
|
||||
}
|
||||
|
||||
var _ VaultsClient = &vaultsClient{}
|
||||
|
||||
func NewVaultsClient(subscriptionID string, credential azcore.TokenCredential, options *arm.ClientOptions) (VaultsClient, error) {
|
||||
client, err := armkeyvault.NewVaultsClient(subscriptionID, credential, options)
|
||||
return vaultsClient{
|
||||
VaultsClient: client,
|
||||
}, err
|
||||
}
|
|
@ -4,5 +4,5 @@ package authorization
|
|||
// Licensed under the Apache License 2.0.
|
||||
|
||||
//go:generate rm -rf ../../../../util/mocks/$GOPACKAGE
|
||||
//go:generate go run ../../../../../vendor/github.com/golang/mock/mockgen -destination=../../../../util/mocks/azureclient/mgmt/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/$GOPACKAGE PermissionsClient,RoleAssignmentsClient,DenyAssignmentClient,RoleDefinitionsClient
|
||||
//go:generate go run ../../../../../vendor/github.com/golang/mock/mockgen -destination=../../../../util/mocks/azureclient/mgmt/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/$GOPACKAGE RoleAssignmentsClient,DenyAssignmentClient,RoleDefinitionsClient
|
||||
//go:generate go run ../../../../../vendor/golang.org/x/tools/cmd/goimports -local=github.com/Azure/ARO-RP -e -w ../../../../util/mocks/azureclient/mgmt/$GOPACKAGE/$GOPACKAGE.go
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package authorization
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient"
|
||||
)
|
||||
|
||||
// PermissionsClient is a minimal interface for azure PermissionsClient
|
||||
type PermissionsClient interface {
|
||||
PermissionsClientAddons
|
||||
}
|
||||
|
||||
type permissionsClient struct {
|
||||
mgmtauthorization.PermissionsClient
|
||||
}
|
||||
|
||||
var _ PermissionsClient = &permissionsClient{}
|
||||
|
||||
// NewPermissionsClient creates a new PermissionsClient
|
||||
func NewPermissionsClient(environment *azureclient.AROEnvironment, subscriptionID string, authorizer autorest.Authorizer) PermissionsClient {
|
||||
client := mgmtauthorization.NewPermissionsClientWithBaseURI(environment.ResourceManagerEndpoint, subscriptionID)
|
||||
client.Authorizer = authorizer
|
||||
|
||||
return &permissionsClient{
|
||||
PermissionsClient: client,
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package authorization
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
)
|
||||
|
||||
// PermissionsClientAddons contains addons for PermissionsClient
|
||||
type PermissionsClientAddons interface {
|
||||
ListForResource(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (permissions []mgmtauthorization.Permission, err error)
|
||||
ListForResourceGroup(ctx context.Context, resourceGroupName string) (permissions []mgmtauthorization.Permission, err error)
|
||||
}
|
||||
|
||||
func (c *permissionsClient) ListForResource(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (permissions []mgmtauthorization.Permission, err error) {
|
||||
page, err := c.PermissionsClient.ListForResource(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
permissions = append(permissions, page.Values()...)
|
||||
|
||||
err = page.NextWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !page.NotDone() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
||||
|
||||
func (c *permissionsClient) ListForResourceGroup(ctx context.Context, resourceGroupName string) (permissions []mgmtauthorization.Permission, error error) {
|
||||
page, err := c.PermissionsClient.ListForResourceGroup(ctx, resourceGroupName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
permissions = append(permissions, page.Values()...)
|
||||
|
||||
err = page.NextWithContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !page.NotDone() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return permissions, nil
|
||||
}
|
|
@ -5,6 +5,7 @@ package compute
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
|
@ -28,6 +29,7 @@ var _ VirtualMachinesClient = &virtualMachinesClient{}
|
|||
func NewVirtualMachinesClient(environment *azureclient.AROEnvironment, subscriptionID string, authorizer autorest.Authorizer) VirtualMachinesClient {
|
||||
client := mgmtcompute.NewVirtualMachinesClientWithBaseURI(environment.ResourceManagerEndpoint, subscriptionID)
|
||||
client.Authorizer = authorizer
|
||||
client.PollingDuration = 30 * time.Minute
|
||||
|
||||
return &virtualMachinesClient{
|
||||
VirtualMachinesClient: client,
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package keyvault
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
mgmtkeyvault "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2019-09-01/keyvault"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient"
|
||||
)
|
||||
|
||||
// VaultsClient is a minimal interface for azure VaultsClient
|
||||
type VaultsClient interface {
|
||||
CheckNameAvailability(ctx context.Context, vaultName mgmtkeyvault.VaultCheckNameAvailabilityParameters) (result mgmtkeyvault.CheckNameAvailabilityResult, err error)
|
||||
}
|
||||
|
||||
type vaultsClient struct {
|
||||
mgmtkeyvault.VaultsClient
|
||||
}
|
||||
|
||||
var _ VaultsClient = &vaultsClient{}
|
||||
|
||||
// NewVaultsClient creates a new KeyvaultClient
|
||||
func NewVaultsClient(environment *azureclient.AROEnvironment, subscriptionID string, authorizer autorest.Authorizer) VaultsClient {
|
||||
client := mgmtkeyvault.NewVaultsClientWithBaseURI(environment.ResourceManagerEndpoint, subscriptionID)
|
||||
client.Authorizer = authorizer
|
||||
|
||||
return &vaultsClient{
|
||||
VaultsClient: client,
|
||||
}
|
||||
}
|
|
@ -4,28 +4,15 @@ package billing
|
|||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
azstorage "github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
"github.com/Azure/ARO-RP/pkg/database"
|
||||
"github.com/Azure/ARO-RP/pkg/database/cosmosdb"
|
||||
"github.com/Azure/ARO-RP/pkg/env"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/storage"
|
||||
"github.com/Azure/ARO-RP/pkg/util/feature"
|
||||
)
|
||||
|
||||
const (
|
||||
tenantIDMSFT = "72f988bf-86f1-41af-91ab-2d7cd011db47"
|
||||
tenantIDAME = "33e01921-4d64-4f8c-a055-5bdaffd5e33d"
|
||||
)
|
||||
|
||||
type Manager interface {
|
||||
|
@ -34,58 +21,19 @@ type Manager interface {
|
|||
}
|
||||
|
||||
type manager struct {
|
||||
storageClient *azstorage.Client
|
||||
billingDB database.Billing
|
||||
subDB database.Subscriptions
|
||||
log *logrus.Entry
|
||||
billingDB database.Billing
|
||||
log *logrus.Entry
|
||||
}
|
||||
|
||||
func NewManager(env env.Interface, billing database.Billing, sub database.Subscriptions, log *logrus.Entry) (Manager, error) {
|
||||
storageClient, err := storageClient(env, billing, sub, log)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &manager{
|
||||
storageClient: storageClient,
|
||||
subDB: sub,
|
||||
billingDB: billing,
|
||||
log: log,
|
||||
billingDB: billing,
|
||||
log: log,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func storageClient(env env.Interface, billing database.Billing, sub database.Subscriptions, log *logrus.Entry) (*azstorage.Client, error) {
|
||||
if os.Getenv("BILLING_E2E_STORAGE_ACCOUNT_ID") == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r, err := azure.ParseResourceID(os.Getenv("BILLING_E2E_STORAGE_ACCOUNT_ID"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localFPAuthorizer, err := env.FPAuthorizer(env.TenantID(), env.Environment().ResourceManagerScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e2estorage := storage.NewAccountsClient(env.Environment(), r.SubscriptionID, localFPAuthorizer)
|
||||
|
||||
keys, err := e2estorage.ListKeys(context.Background(), r.ResourceGroup, r.ResourceName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := azstorage.NewBasicClient(r.ResourceName, *(*keys.Keys)[0].Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
func (m *manager) Ensure(ctx context.Context, doc *api.OpenShiftClusterDocument, sub *api.SubscriptionDocument) error {
|
||||
billingDoc, err := m.billingDB.Create(ctx, &api.BillingDocument{
|
||||
_, err := m.billingDB.Create(ctx, &api.BillingDocument{
|
||||
ID: doc.ID,
|
||||
Key: doc.Key,
|
||||
ClusterResourceGroupIDKey: doc.ClusterResourceGroupIDKey,
|
||||
|
@ -104,16 +52,12 @@ func (m *manager) Ensure(ctx context.Context, doc *api.OpenShiftClusterDocument,
|
|||
return err
|
||||
}
|
||||
|
||||
if e2eErr := m.createOrUpdateE2EBlob(ctx, billingDoc); e2eErr != nil {
|
||||
m.log.Warnf("createOrUpdateE2EBlob failed: %s", e2eErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) Delete(ctx context.Context, doc *api.OpenShiftClusterDocument) error {
|
||||
m.log.Printf("updating billing record with deletion time")
|
||||
billingDoc, err := m.billingDB.MarkForDeletion(ctx, doc.ID)
|
||||
_, err := m.billingDB.MarkForDeletion(ctx, doc.ID)
|
||||
if cosmosdb.IsErrorStatusCode(err, http.StatusNotFound) {
|
||||
return nil
|
||||
}
|
||||
|
@ -121,67 +65,5 @@ func (m *manager) Delete(ctx context.Context, doc *api.OpenShiftClusterDocument)
|
|||
return err
|
||||
}
|
||||
|
||||
if e2eErr := m.createOrUpdateE2EBlob(ctx, billingDoc); e2eErr != nil {
|
||||
// We are not failing the operation if we cannot write to e2e storage account, just warning
|
||||
m.log.Warnf("createOrUpdateE2EBlob failed: %s", e2eErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isSubscriptionRegisteredForE2E returns true if the subscription has the
|
||||
// "Microsoft.RedHatOpenShift/SaveAROTestConfig" feature registered
|
||||
func isSubscriptionRegisteredForE2E(sub *api.SubscriptionProperties) bool {
|
||||
if sub.TenantID == tenantIDMSFT || sub.TenantID == tenantIDAME {
|
||||
return feature.IsRegisteredForFeature(sub, api.FeatureFlagSaveAROTestConfig)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// createOrUpdateE2Eblob create a copy of the billing document in the e2e
|
||||
// storage account. This is used later on by the billing e2e
|
||||
func (m *manager) createOrUpdateE2EBlob(ctx context.Context, doc *api.BillingDocument) error {
|
||||
//skip updating the storage account if this is a dev scenario
|
||||
if m.storageClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate if E2E Feature is registered
|
||||
resource, err := azure.ParseResourceID(doc.Key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subscriptionDoc, err := m.subDB.Get(ctx, resource.SubscriptionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !isSubscriptionRegisteredForE2E(subscriptionDoc.Subscription.Properties) {
|
||||
return nil
|
||||
}
|
||||
|
||||
blobclient := m.storageClient.GetBlobService()
|
||||
|
||||
containerName := strings.ToLower("bill-" + doc.Billing.Location + "-" + resource.ResourceGroup + "-" + resource.ResourceName)
|
||||
if len(containerName) > 63 {
|
||||
containerName = containerName[:63]
|
||||
}
|
||||
|
||||
// The following is added to get rid of the '-' at the end in order to avoid an invalid container name.
|
||||
containerName = strings.TrimSuffix(containerName, "-")
|
||||
|
||||
containerRef := blobclient.GetContainerReference(containerName)
|
||||
_, err = containerRef.CreateIfNotExists(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blobRef := containerRef.GetBlobReference("billingentity")
|
||||
b, err := json.Marshal(doc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return blobRef.CreateBlockBlobFromReader(bytes.NewReader(b), nil)
|
||||
}
|
||||
|
|
|
@ -19,101 +19,6 @@ import (
|
|||
utilerror "github.com/Azure/ARO-RP/test/util/error"
|
||||
)
|
||||
|
||||
func TestIsSubscriptionRegisteredForE2E(t *testing.T) {
|
||||
const tenantID = "11111111-1111-1111-1111-111111111111"
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
sub api.SubscriptionProperties
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
},
|
||||
{
|
||||
name: "sub without feature flag registered and not internal tenant",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantID,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: "RandomFeature",
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sub with feature flag registered and not internal tenant",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantID,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AME internal tenant and feature flag not registered",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantIDAME,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: "RandomFeature",
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MSFT internal tenant and feature flag not registered",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantIDMSFT,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: "RandomFeature",
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AME internal tenant and feature flag registered",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantIDAME,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "MSFT internal tenant and feature flag registered",
|
||||
sub: api.SubscriptionProperties{
|
||||
TenantID: tenantIDMSFT,
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "Registered",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := isSubscriptionRegisteredForE2E(&tt.sub)
|
||||
if got != tt.want {
|
||||
t.Error(got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
|
@ -220,7 +125,6 @@ func TestDelete(t *testing.T) {
|
|||
m := &manager{
|
||||
log: log,
|
||||
billingDB: billingDatabase,
|
||||
subDB: subscriptionsDatabase,
|
||||
}
|
||||
|
||||
err = m.Delete(ctx, &api.OpenShiftClusterDocument{ID: docID})
|
||||
|
@ -279,12 +183,6 @@ func TestEnsure(t *testing.T) {
|
|||
ID: subID,
|
||||
Subscription: &api.Subscription{
|
||||
Properties: &api.SubscriptionProperties{
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "NotRegistered",
|
||||
},
|
||||
},
|
||||
TenantID: tenantID,
|
||||
},
|
||||
},
|
||||
|
@ -321,12 +219,6 @@ func TestEnsure(t *testing.T) {
|
|||
ID: subID,
|
||||
Subscription: &api.Subscription{
|
||||
Properties: &api.SubscriptionProperties{
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "NotRegistered",
|
||||
},
|
||||
},
|
||||
TenantID: tenantID,
|
||||
},
|
||||
},
|
||||
|
@ -353,12 +245,6 @@ func TestEnsure(t *testing.T) {
|
|||
ID: subID,
|
||||
Subscription: &api.Subscription{
|
||||
Properties: &api.SubscriptionProperties{
|
||||
RegisteredFeatures: []api.RegisteredFeatureProfile{
|
||||
{
|
||||
Name: api.FeatureFlagSaveAROTestConfig,
|
||||
State: "NotRegistered",
|
||||
},
|
||||
},
|
||||
TenantID: tenantID,
|
||||
},
|
||||
},
|
||||
|
@ -408,7 +294,6 @@ func TestEnsure(t *testing.T) {
|
|||
m := &manager{
|
||||
log: log,
|
||||
billingDB: billingDatabase,
|
||||
subDB: subscriptionsDatabase,
|
||||
}
|
||||
|
||||
doc, err := openShiftClusterDatabase.Get(ctx, strings.ToLower(testdatabase.GetResourcePath(subID, "resourceName")))
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestEnsureDeleted(t *testing.T) {
|
|||
})
|
||||
|
||||
client := testclienthelper.NewHookingClient(builder.Build()).
|
||||
WithDeleteHook(func(obj client.Object) error {
|
||||
WithPreDeleteHook(func(obj client.Object) error {
|
||||
if obj.GetName() == "test-name-2" {
|
||||
return fmt.Errorf("error on %s", obj.GetName())
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ func TestEnsureDeleted(t *testing.T) {
|
|||
Namespace: "test-ns-2",
|
||||
})
|
||||
if err == nil {
|
||||
t.Errorf("function should handle failure response (non-404) correctly")
|
||||
t.Error(fmt.Errorf("function should handle failure response (non-404) correctly: %w", err))
|
||||
}
|
||||
|
||||
err = ch.EnsureDeleted(ctx, schema.GroupVersionKind{Group: "core", Version: "v1", Kind: "ConfigMap"},
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
|
@ -15,8 +16,10 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
armsdk "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"
|
||||
mgmtkeyvault "github.com/Azure/azure-sdk-for-go/services/keyvault/mgmt/2019-09-01/keyvault"
|
||||
sdkkeyvault "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault"
|
||||
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
mgmtfeatures "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/features"
|
||||
|
@ -34,9 +37,9 @@ import (
|
|||
"github.com/Azure/ARO-RP/pkg/deploy/generator"
|
||||
"github.com/Azure/ARO-RP/pkg/env"
|
||||
"github.com/Azure/ARO-RP/pkg/util/arm"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armkeyvault"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/authorization"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/features"
|
||||
keyvaultclient "github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/keyvault"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
|
||||
redhatopenshift20200430 "github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/redhatopenshift/2020-04-30/redhatopenshift"
|
||||
redhatopenshift20210901preview "github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/redhatopenshift/2021-09-01-preview/redhatopenshift"
|
||||
|
@ -67,20 +70,7 @@ type Cluster struct {
|
|||
roleassignments authorization.RoleAssignmentsClient
|
||||
peerings network.VirtualNetworkPeeringsClient
|
||||
ciParentVnetPeerings network.VirtualNetworkPeeringsClient
|
||||
vaultsClient keyvaultclient.VaultsClient
|
||||
}
|
||||
|
||||
type errors []error
|
||||
|
||||
func (errs errors) Error() string {
|
||||
var sb strings.Builder
|
||||
|
||||
for _, err := range errs {
|
||||
sb.WriteString(err.Error())
|
||||
sb.WriteByte('\n')
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
vaultsClient armkeyvault.VaultsClient
|
||||
}
|
||||
|
||||
func New(log *logrus.Entry, environment env.Core, ci bool) (*Cluster, error) {
|
||||
|
@ -91,6 +81,7 @@ func New(log *logrus.Entry, environment env.Core, ci bool) (*Cluster, error) {
|
|||
}
|
||||
|
||||
options := environment.Environment().EnvironmentCredentialOptions()
|
||||
|
||||
spTokenCredential, err := azidentity.NewEnvironmentCredential(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -104,6 +95,17 @@ func New(log *logrus.Entry, environment env.Core, ci bool) (*Cluster, error) {
|
|||
scopes := []string{environment.Environment().ResourceManagerScope}
|
||||
authorizer := azidext.NewTokenCredentialAdapter(spTokenCredential, scopes)
|
||||
|
||||
armOption := armsdk.ClientOptions{
|
||||
ClientOptions: policy.ClientOptions{
|
||||
Cloud: options.Cloud,
|
||||
},
|
||||
}
|
||||
|
||||
vaultClient, err := armkeyvault.NewVaultsClient(environment.SubscriptionID(), spTokenCredential, &armOption)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &Cluster{
|
||||
log: log,
|
||||
env: environment,
|
||||
|
@ -121,7 +123,7 @@ func New(log *logrus.Entry, environment env.Core, ci bool) (*Cluster, error) {
|
|||
routetables: network.NewRouteTablesClient(environment.Environment(), environment.SubscriptionID(), authorizer),
|
||||
roleassignments: authorization.NewRoleAssignmentsClient(environment.Environment(), environment.SubscriptionID(), authorizer),
|
||||
peerings: network.NewVirtualNetworkPeeringsClient(environment.Environment(), environment.SubscriptionID(), authorizer),
|
||||
vaultsClient: keyvaultclient.NewVaultsClient(environment.Environment(), environment.SubscriptionID(), authorizer),
|
||||
vaultsClient: vaultClient,
|
||||
}
|
||||
|
||||
if ci && env.IsLocalDevelopmentMode() {
|
||||
|
@ -232,7 +234,8 @@ func (c *Cluster) Create(ctx context.Context, vnetResourceGroup, clusterName str
|
|||
if c.ci {
|
||||
// name is limited to 24 characters, but must be globally unique, so we generate one and try if it is available
|
||||
kvName = "kv-" + uuid.DefaultGenerator.Generate()[:21]
|
||||
result, err := c.vaultsClient.CheckNameAvailability(ctx, mgmtkeyvault.VaultCheckNameAvailabilityParameters{Name: &kvName, Type: to.StringPtr("Microsoft.KeyVault/vaults")})
|
||||
|
||||
result, err := c.vaultsClient.CheckNameAvailability(ctx, sdkkeyvault.VaultCheckNameAvailabilityParameters{Name: &kvName, Type: to.StringPtr("Microsoft.KeyVault/vaults")}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -381,75 +384,28 @@ func (c *Cluster) generateSubnets() (vnetPrefix string, masterSubnet string, wor
|
|||
}
|
||||
|
||||
func (c *Cluster) Delete(ctx context.Context, vnetResourceGroup, clusterName string) error {
|
||||
var errs errors
|
||||
var errs []error
|
||||
|
||||
oc, err := c.openshiftclustersv20200430.Get(ctx, vnetResourceGroup, clusterName)
|
||||
if err == nil {
|
||||
c.log.Print("deleting role assignments")
|
||||
err = c.deleteRoleAssignments(ctx, vnetResourceGroup, *oc.OpenShiftClusterProperties.ServicePrincipalProfile.ClientID)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
c.log.Print("deleting cluster")
|
||||
err = c.openshiftclustersv20200430.DeleteAndWait(ctx, vnetResourceGroup, clusterName)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if c.ci {
|
||||
_, err = c.groups.Get(ctx, vnetResourceGroup)
|
||||
if err == nil {
|
||||
c.log.Print("deleting resource group")
|
||||
err = c.groups.DeleteAndWait(ctx, vnetResourceGroup)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
// Only delete peering if CI=true and RP_MODE=development
|
||||
if env.IsLocalDevelopmentMode() {
|
||||
r, err := azure.ParseResourceID(c.ciParentVnet)
|
||||
if err == nil {
|
||||
err = c.ciParentVnetPeerings.DeleteAndWait(ctx, r.ResourceGroup, r.ResourceName, vnetResourceGroup+"-peer")
|
||||
}
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Deleting the deployment does not clean up the associated resources
|
||||
c.log.Info("deleting deployment")
|
||||
err = c.deployments.DeleteAndWait(ctx, vnetResourceGroup, clusterName)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
c.log.Info("deleting master/worker subnets")
|
||||
err = c.subnets.DeleteAndWait(ctx, vnetResourceGroup, "dev-vnet", clusterName+"-master")
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
err = c.subnets.DeleteAndWait(ctx, vnetResourceGroup, "dev-vnet", clusterName+"-worker")
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
c.log.Info("deleting route table")
|
||||
err = c.routetables.DeleteAndWait(ctx, vnetResourceGroup, clusterName+"-rt")
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
switch {
|
||||
case c.ci && env.IsLocalDevelopmentMode(): // PR E2E
|
||||
errs = append(errs,
|
||||
c.deleteCluster(ctx, vnetResourceGroup, clusterName),
|
||||
c.deleteClusterResourceGroup(ctx, vnetResourceGroup),
|
||||
c.deleteVnetPeerings(ctx, vnetResourceGroup),
|
||||
)
|
||||
case c.ci: // Prod E2E
|
||||
errs = append(errs, c.deleteClusterResourceGroup(ctx, vnetResourceGroup))
|
||||
default:
|
||||
errs = append(errs,
|
||||
c.deleteRoleAssignments(ctx, vnetResourceGroup, clusterName),
|
||||
c.deleteCluster(ctx, vnetResourceGroup, clusterName),
|
||||
c.deleteDeployment(ctx, vnetResourceGroup, clusterName), // Deleting the deployment does not clean up the associated resources
|
||||
c.deleteVnetResources(ctx, vnetResourceGroup, "dev-vnet", clusterName),
|
||||
)
|
||||
}
|
||||
|
||||
c.log.Info("done")
|
||||
|
||||
if errs != nil {
|
||||
return errs // https://golang.org/doc/faq#nil_error
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
// createCluster created new clusters, based on where it is running.
|
||||
|
@ -647,10 +603,15 @@ func (c *Cluster) fixupNSGs(ctx context.Context, vnetResourceGroup, clusterName
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteRoleAssignments(ctx context.Context, vnetResourceGroup, appID string) error {
|
||||
spObjID, err := utilgraph.GetServicePrincipalIDByAppID(ctx, c.spGraphClient, appID)
|
||||
func (c *Cluster) deleteRoleAssignments(ctx context.Context, vnetResourceGroup, clusterName string) error {
|
||||
c.log.Print("deleting role assignments")
|
||||
oc, err := c.openshiftclustersv20200430.Get(ctx, vnetResourceGroup, clusterName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error getting cluster document: %w", err)
|
||||
}
|
||||
spObjID, err := utilgraph.GetServicePrincipalIDByAppID(ctx, c.spGraphClient, *oc.OpenShiftClusterProperties.ServicePrincipalProfile.ClientID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting service principal for cluster: %w", err)
|
||||
}
|
||||
if spObjID == nil {
|
||||
return nil
|
||||
|
@ -658,7 +619,7 @@ func (c *Cluster) deleteRoleAssignments(ctx context.Context, vnetResourceGroup,
|
|||
|
||||
roleAssignments, err := c.roleassignments.ListForResourceGroup(ctx, vnetResourceGroup, fmt.Sprintf("principalId eq '%s'", *spObjID))
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error listing role assignments for service principal: %w", err)
|
||||
}
|
||||
|
||||
for _, roleAssignment := range roleAssignments {
|
||||
|
@ -670,7 +631,7 @@ func (c *Cluster) deleteRoleAssignments(ctx context.Context, vnetResourceGroup,
|
|||
c.log.Infof("deleting role assignment %s", *roleAssignment.Name)
|
||||
_, err = c.roleassignments.Delete(ctx, *roleAssignment.Scope, *roleAssignment.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error deleting role assignment %s: %w", *roleAssignment.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -678,6 +639,71 @@ func (c *Cluster) deleteRoleAssignments(ctx context.Context, vnetResourceGroup,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteCluster(ctx context.Context, resourceGroup, clusterName string) error {
|
||||
c.log.Printf("deleting cluster %s", clusterName)
|
||||
if err := c.openshiftclustersv20200430.DeleteAndWait(ctx, resourceGroup, clusterName); err != nil {
|
||||
return fmt.Errorf("error deleting cluster %s: %w", clusterName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteClusterResourceGroup(ctx context.Context, resourceGroup string) error {
|
||||
if _, err := c.groups.Get(ctx, resourceGroup); err != nil {
|
||||
c.log.Printf("error getting resource group %s, skipping deletion: %v", resourceGroup, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.log.Printf("deleting resource group %s", resourceGroup)
|
||||
if err := c.groups.DeleteAndWait(ctx, resourceGroup); err != nil {
|
||||
return fmt.Errorf("error deleting resource group: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteVnetPeerings(ctx context.Context, resourceGroup string) error {
|
||||
r, err := azure.ParseResourceID(c.ciParentVnet)
|
||||
if err == nil {
|
||||
err = c.ciParentVnetPeerings.DeleteAndWait(ctx, r.ResourceGroup, r.ResourceName, resourceGroup+"-peer")
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting vnet peerings: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteDeployment(ctx context.Context, resourceGroup, clusterName string) error {
|
||||
c.log.Info("deleting deployment")
|
||||
if err := c.deployments.DeleteAndWait(ctx, resourceGroup, clusterName); err != nil {
|
||||
return fmt.Errorf("error deleting deployment: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) deleteVnetResources(ctx context.Context, resourceGroup, vnetName, clusterName string) error {
|
||||
var errs []error
|
||||
|
||||
c.log.Info("deleting master/worker subnets")
|
||||
if err := c.subnets.DeleteAndWait(ctx, resourceGroup, vnetName, clusterName+"-master"); err != nil {
|
||||
c.log.Errorf("error when deleting master subnet: %v", err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if err := c.subnets.DeleteAndWait(ctx, resourceGroup, vnetName, clusterName+"-worker"); err != nil {
|
||||
c.log.Errorf("error when deleting worker subnet: %v", err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
c.log.Info("deleting route table")
|
||||
if err := c.routetables.DeleteAndWait(ctx, resourceGroup, clusterName+"-rt"); err != nil {
|
||||
c.log.Errorf("error when deleting route table: %v", err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (c *Cluster) peerSubnetsToCI(ctx context.Context, vnetResourceGroup, clusterName string) error {
|
||||
cluster := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/dev-vnet", c.env.SubscriptionID(), vnetResourceGroup)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/authorization (interfaces: PermissionsClient,RoleAssignmentsClient,DenyAssignmentClient,RoleDefinitionsClient)
|
||||
// Source: github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/authorization (interfaces: RoleAssignmentsClient,DenyAssignmentClient,RoleDefinitionsClient)
|
||||
|
||||
// Package mock_authorization is a generated GoMock package.
|
||||
package mock_authorization
|
||||
|
@ -12,59 +12,6 @@ import (
|
|||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockPermissionsClient is a mock of PermissionsClient interface.
|
||||
type MockPermissionsClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPermissionsClientMockRecorder
|
||||
}
|
||||
|
||||
// MockPermissionsClientMockRecorder is the mock recorder for MockPermissionsClient.
|
||||
type MockPermissionsClientMockRecorder struct {
|
||||
mock *MockPermissionsClient
|
||||
}
|
||||
|
||||
// NewMockPermissionsClient creates a new mock instance.
|
||||
func NewMockPermissionsClient(ctrl *gomock.Controller) *MockPermissionsClient {
|
||||
mock := &MockPermissionsClient{ctrl: ctrl}
|
||||
mock.recorder = &MockPermissionsClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPermissionsClient) EXPECT() *MockPermissionsClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ListForResource mocks base method.
|
||||
func (m *MockPermissionsClient) ListForResource(arg0 context.Context, arg1, arg2, arg3, arg4, arg5 string) ([]authorization.Permission, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListForResource", arg0, arg1, arg2, arg3, arg4, arg5)
|
||||
ret0, _ := ret[0].([]authorization.Permission)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListForResource indicates an expected call of ListForResource.
|
||||
func (mr *MockPermissionsClientMockRecorder) ListForResource(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListForResource", reflect.TypeOf((*MockPermissionsClient)(nil).ListForResource), arg0, arg1, arg2, arg3, arg4, arg5)
|
||||
}
|
||||
|
||||
// ListForResourceGroup mocks base method.
|
||||
func (m *MockPermissionsClient) ListForResourceGroup(arg0 context.Context, arg1 string) ([]authorization.Permission, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListForResourceGroup", arg0, arg1)
|
||||
ret0, _ := ret[0].([]authorization.Permission)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListForResourceGroup indicates an expected call of ListForResourceGroup.
|
||||
func (mr *MockPermissionsClientMockRecorder) ListForResourceGroup(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListForResourceGroup", reflect.TypeOf((*MockPermissionsClient)(nil).ListForResourceGroup), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockRoleAssignmentsClient is a mock of RoleAssignmentsClient interface.
|
||||
type MockRoleAssignmentsClient struct {
|
||||
ctrl *gomock.Controller
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package permissions
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
)
|
||||
|
||||
// CanDoAction returns true if a given action is granted by a set of permissions
|
||||
func CanDoAction(ps []mgmtauthorization.Permission, a string) (bool, error) {
|
||||
for _, p := range ps {
|
||||
var matched bool
|
||||
|
||||
for _, action := range *p.Actions {
|
||||
action := regexp.QuoteMeta(action)
|
||||
action = "(?i)^" + strings.ReplaceAll(action, `\*`, ".*") + "$"
|
||||
rx, err := regexp.Compile(action)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rx.MatchString(a) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, notAction := range *p.NotActions {
|
||||
notAction := regexp.QuoteMeta(notAction)
|
||||
notAction = "(?i)^" + strings.ReplaceAll(notAction, `\*`, ".*") + "$"
|
||||
rx, err := regexp.Compile(notAction)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if rx.MatchString(a) {
|
||||
matched = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if matched {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package permissions
|
||||
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the Apache License 2.0.
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
)
|
||||
|
||||
func TestCanDoAction(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
permissions []mgmtauthorization.Permission
|
||||
action string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "empty permissions list",
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
},
|
||||
{
|
||||
name: "has permission - exact",
|
||||
permissions: []mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{"Microsoft.Compute/virtualMachines/*"},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
{
|
||||
Actions: &[]string{"Microsoft.Network/virtualNetworks/subnets/join/action"},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
},
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "has permission - wildcard",
|
||||
permissions: []mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Network/virtualNetworks/subnets/*/action"},
|
||||
NotActions: &[]string{},
|
||||
}},
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "has permission - exact, conflict",
|
||||
permissions: []mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{"Microsoft.Network/virtualNetworks/subnets/join/action"},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
{
|
||||
Actions: &[]string{},
|
||||
NotActions: &[]string{"Microsoft.Network/virtualNetworks/subnets/join/action"},
|
||||
},
|
||||
},
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "has permission excluded - exact",
|
||||
permissions: []mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Network/*"},
|
||||
NotActions: &[]string{"Microsoft.Network/virtualNetworks/subnets/join/action"},
|
||||
}},
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
},
|
||||
{
|
||||
name: "has permission excluded - wildcard",
|
||||
permissions: []mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Network/*"},
|
||||
NotActions: &[]string{"Microsoft.Network/virtualNetworks/subnets/*/action"},
|
||||
}},
|
||||
action: "Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ok, err := CanDoAction(test.permissions, test.action)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %#v", err)
|
||||
}
|
||||
|
||||
if ok != test.want {
|
||||
t.Errorf("expected result %#v, got %#v", test.want, ok)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ import (
|
|||
"testing"
|
||||
|
||||
mgmtcompute "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
|
@ -19,7 +18,10 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
mock_authorization "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/authorization"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/authz/remotepdp"
|
||||
mock_remotepdp "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/authz/remotepdp"
|
||||
mock_azcore "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/azcore"
|
||||
mock_compute "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/compute"
|
||||
utilerror "github.com/Azure/ARO-RP/test/util/error"
|
||||
)
|
||||
|
@ -44,10 +46,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
|
||||
t.Run(string(authorizerType), func(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
oc *api.OpenShiftCluster
|
||||
mocks func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc)
|
||||
wantErr string
|
||||
name string
|
||||
oc *api.OpenShiftCluster
|
||||
actionInfos []remotepdp.ActionInfo
|
||||
mocks func(*mock_compute.MockDiskEncryptionSetsClient, *mock_remotepdp.MockRemotePDPClient, *mock_azcore.MockTokenCredential, context.CancelFunc)
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "no disk encryption set provided",
|
||||
|
@ -66,13 +69,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(validDiskEncryptionAuthorizationDecision, nil)
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{Location: to.StringPtr("eastus")}, nil)
|
||||
|
@ -91,13 +92,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(validDiskEncryptionAuthorizationDecision, nil)
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{Location: to.StringPtr("eastus")}, nil)
|
||||
|
@ -116,19 +115,21 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR2.ResourceGroup, fakeDesR2.Provider, "", fakeDesR2.ResourceType, fakeDesR2.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(_ context.Context, authReq remotepdp.AuthorizationRequest) (*remotepdp.AuthorizationDecisionResponse, error) {
|
||||
cancel() // wait.PollImmediateUntil will always be invoked at least once
|
||||
switch authReq.Resource.Id {
|
||||
case fakeDesR1.String():
|
||||
return validDiskEncryptionAuthorizationDecision, nil
|
||||
case fakeDesR2.String():
|
||||
return validDiskEncryptionAuthorizationDecision, nil
|
||||
}
|
||||
return invalidDiskEncryptionAuthorizationDecisionsReadNotAllowed, nil
|
||||
},
|
||||
).AnyTimes()
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{Location: to.StringPtr("eastus")}, nil)
|
||||
|
@ -150,13 +151,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(validDiskEncryptionAuthorizationDecision, nil)
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{}, autorest.DetailedError{StatusCode: http.StatusNotFound})
|
||||
|
@ -176,9 +175,10 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(nil, errors.New("fakeerr"))
|
||||
},
|
||||
wantErr: "fakeerr",
|
||||
|
@ -196,13 +196,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(validDiskEncryptionAuthorizationDecision, nil)
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{}, errors.New("fakeerr"))
|
||||
|
@ -222,10 +220,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Do(func(arg0, arg1 interface{}) {
|
||||
cancel()
|
||||
})
|
||||
},
|
||||
|
@ -244,16 +243,21 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR2.ResourceGroup, fakeDesR2.Provider, "", fakeDesR2.ResourceType, fakeDesR2.ResourceName).
|
||||
Return(nil, autorest.DetailedError{StatusCode: http.StatusNotFound})
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(_ context.Context, authReq remotepdp.AuthorizationRequest) (*remotepdp.AuthorizationDecisionResponse, error) {
|
||||
cancel() // wait.PollImmediateUntil will always be invoked at least once
|
||||
switch authReq.Resource.Id {
|
||||
case fakeDesR1.String():
|
||||
return validDiskEncryptionAuthorizationDecision, nil
|
||||
case fakeDesR2.String():
|
||||
return nil, autorest.DetailedError{StatusCode: http.StatusNotFound}
|
||||
}
|
||||
return invalidDiskEncryptionAuthorizationDecisionsReadNotAllowed, nil
|
||||
},
|
||||
).AnyTimes()
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{Location: to.StringPtr("eastus")}, nil)
|
||||
|
@ -273,13 +277,11 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
},
|
||||
mocks: func(permissions *mock_authorization.MockPermissionsClient, diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, cancel context.CancelFunc) {
|
||||
permissions.EXPECT().
|
||||
ListForResource(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.Provider, "", fakeDesR1.ResourceType, fakeDesR1.ResourceName).
|
||||
Return([]mgmtauthorization.Permission{{
|
||||
Actions: &[]string{"Microsoft.Compute/diskEncryptionSets/read"},
|
||||
NotActions: &[]string{},
|
||||
}}, nil)
|
||||
mocks: func(diskEncryptionSets *mock_compute.MockDiskEncryptionSetsClient, pdpClient *mock_remotepdp.MockRemotePDPClient, tokenCred *mock_azcore.MockTokenCredential, cancel context.CancelFunc) {
|
||||
mockTokenCredential(tokenCred)
|
||||
pdpClient.EXPECT().
|
||||
CheckAccess(gomock.Any(), gomock.Any()).
|
||||
Return(validDiskEncryptionAuthorizationDecision, nil)
|
||||
diskEncryptionSets.EXPECT().
|
||||
Get(gomock.Any(), fakeDesR1.ResourceGroup, fakeDesR1.ResourceName).
|
||||
Return(mgmtcompute.DiskEncryptionSet{Location: to.StringPtr("westeurope")}, nil)
|
||||
|
@ -294,18 +296,21 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
permissionsClient := mock_authorization.NewMockPermissionsClient(controller)
|
||||
diskEncryptionSetsClient := mock_compute.NewMockDiskEncryptionSetsClient(controller)
|
||||
tokenCred := mock_azcore.NewMockTokenCredential(controller)
|
||||
remotePDPClient := mock_remotepdp.NewMockRemotePDPClient(controller)
|
||||
|
||||
if tt.mocks != nil {
|
||||
tt.mocks(permissionsClient, diskEncryptionSetsClient, cancel)
|
||||
tt.mocks(diskEncryptionSetsClient, remotePDPClient, tokenCred, cancel)
|
||||
}
|
||||
|
||||
dv := &dynamic{
|
||||
authorizerType: authorizerType,
|
||||
log: logrus.NewEntry(logrus.StandardLogger()),
|
||||
permissions: permissionsClient,
|
||||
diskEncryptionSets: diskEncryptionSetsClient,
|
||||
azEnv: &azureclient.PublicCloud,
|
||||
authorizerType: authorizerType,
|
||||
log: logrus.NewEntry(logrus.StandardLogger()),
|
||||
diskEncryptionSets: diskEncryptionSetsClient,
|
||||
pdpClient: remotePDPClient,
|
||||
checkAccessSubjectInfoCred: tokenCred,
|
||||
}
|
||||
|
||||
err := dv.ValidateDiskEncryptionSets(ctx, tt.oc)
|
||||
|
@ -315,3 +320,22 @@ func TestValidateDiskEncryptionSets(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
invalidDiskEncryptionAuthorizationDecisionsReadNotAllowed = &remotepdp.AuthorizationDecisionResponse{
|
||||
Value: []remotepdp.AuthorizationDecision{
|
||||
{
|
||||
ActionId: "Microsoft.Compute/diskEncryptionSets/read",
|
||||
AccessDecision: remotepdp.NotAllowed,
|
||||
},
|
||||
},
|
||||
}
|
||||
validDiskEncryptionAuthorizationDecision = &remotepdp.AuthorizationDecisionResponse{
|
||||
Value: []remotepdp.AuthorizationDecision{
|
||||
{
|
||||
ActionId: "Microsoft.Compute/diskEncryptionSets/read",
|
||||
AccessDecision: remotepdp.Allowed,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -25,11 +25,8 @@ import (
|
|||
"github.com/Azure/ARO-RP/pkg/env"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/authz/remotepdp"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/authorization"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/compute"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/mgmt/network"
|
||||
"github.com/Azure/ARO-RP/pkg/util/permissions"
|
||||
"github.com/Azure/ARO-RP/pkg/util/steps"
|
||||
"github.com/Azure/ARO-RP/pkg/util/token"
|
||||
)
|
||||
|
||||
|
@ -87,7 +84,6 @@ type dynamic struct {
|
|||
env env.Interface
|
||||
azEnv *azureclient.AROEnvironment
|
||||
|
||||
permissions authorization.PermissionsClient
|
||||
virtualNetworks virtualNetworksGetClient
|
||||
diskEncryptionSets compute.DiskEncryptionSetsClient
|
||||
resourceSkusClient compute.ResourceSkusClient
|
||||
|
@ -125,7 +121,6 @@ func NewValidator(
|
|||
|
||||
spComputeUsage: compute.NewUsageClient(azEnv, subscriptionID, authorizer),
|
||||
spNetworkUsage: network.NewUsageClient(azEnv, subscriptionID, authorizer),
|
||||
permissions: authorization.NewPermissionsClient(azEnv, subscriptionID, authorizer),
|
||||
virtualNetworks: newVirtualNetworksCache(
|
||||
network.NewVirtualNetworksClient(azEnv, subscriptionID, authorizer),
|
||||
),
|
||||
|
@ -397,12 +392,8 @@ func (dv *dynamic) validateActions(ctx context.Context, r *azure.Resource, actio
|
|||
defer cancel()
|
||||
|
||||
c := closure{dv: dv, ctx: ctx, resource: r, actions: actions}
|
||||
conditionalFunc := c.usingListPermissions
|
||||
if dv.pdpClient != nil {
|
||||
conditionalFunc = c.usingCheckAccessV2
|
||||
}
|
||||
|
||||
return wait.PollImmediateUntil(30*time.Second, conditionalFunc, timeoutCtx.Done())
|
||||
return wait.PollImmediateUntil(30*time.Second, c.usingCheckAccessV2, timeoutCtx.Done())
|
||||
}
|
||||
|
||||
// closure is the closure used in PollImmediateUntil's ConditionalFunc
|
||||
|
@ -414,47 +405,8 @@ type closure struct {
|
|||
oid *string
|
||||
}
|
||||
|
||||
// usingListPermissions is how the current check is done
|
||||
func (c closure) usingListPermissions() (bool, error) {
|
||||
c.dv.log.Debug("retry validateActions with ListPermissions")
|
||||
perms, err := c.dv.permissions.ListForResource(
|
||||
c.ctx,
|
||||
c.resource.ResourceGroup,
|
||||
c.resource.Provider,
|
||||
"",
|
||||
c.resource.ResourceType,
|
||||
c.resource.ResourceName,
|
||||
)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// If we get a StatusForbidden, try refreshing the SP (since with a
|
||||
// brand-new SP it might take time to propagate)
|
||||
if detailedErr, ok := err.(autorest.DetailedError); ok &&
|
||||
detailedErr.StatusCode == http.StatusForbidden {
|
||||
return false, steps.ErrWantRefresh
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, action := range c.actions {
|
||||
ok, err := permissions.CanDoAction(perms, action)
|
||||
if !ok || err != nil {
|
||||
// TODO(jminter): I don't understand if there are genuinely
|
||||
// cases where CanDoAction can return false then true shortly
|
||||
// after. I'm a little skeptical; if it can't happen we can
|
||||
// simplify this code. We should add a metric on this.
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// usingCheckAccessV2 uses the new RBAC checkAccessV2 API
|
||||
func (c closure) usingCheckAccessV2() (bool, error) {
|
||||
// TODO remove this when fully migrated to CheckAccess
|
||||
c.dv.log.Info("validateActions with CheckAccessV2")
|
||||
|
||||
// reusing oid during retries
|
||||
|
|
|
@ -7,14 +7,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
mgmtnetwork "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2020-08-01/network"
|
||||
mgmtauthorization "github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-09-01-preview/authorization"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/golang/mock/gomock"
|
||||
|
@ -25,7 +22,6 @@ import (
|
|||
"github.com/Azure/ARO-RP/pkg/util/azureclient/authz/remotepdp"
|
||||
mock_remotepdp "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/authz/remotepdp"
|
||||
mock_azcore "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/azcore"
|
||||
mock_authorization "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/authorization"
|
||||
mock_network "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/mgmt/network"
|
||||
utilerror "github.com/Azure/ARO-RP/test/util/error"
|
||||
)
|
||||
|
@ -48,122 +44,6 @@ var (
|
|||
workerNSGv1 = resourceGroupID + "/providers/Microsoft.Network/networkSecurityGroups/aro-node-nsg"
|
||||
)
|
||||
|
||||
func TestValidateVnetPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
resourceType := "virtualNetworks"
|
||||
resourceProvider := "Microsoft.Network"
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
mocks func(*mock_authorization.MockPermissionsClient, context.CancelFunc)
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "pass",
|
||||
mocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, resourceProvider, "", resourceType, vnetName).
|
||||
Return([]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{
|
||||
"Microsoft.Network/virtualNetworks/join/action",
|
||||
"Microsoft.Network/virtualNetworks/read",
|
||||
"Microsoft.Network/virtualNetworks/write",
|
||||
"Microsoft.Network/virtualNetworks/subnets/join/action",
|
||||
"Microsoft.Network/virtualNetworks/subnets/read",
|
||||
"Microsoft.Network/virtualNetworks/subnets/write",
|
||||
},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fail: missing permissions",
|
||||
mocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, resourceProvider, "", resourceType, vnetName).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
cancel()
|
||||
}).
|
||||
Return(
|
||||
[]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
},
|
||||
wantErr: "400: InvalidServicePrincipalPermissions: : The cluster service principal (Application ID: fff51942-b1f9-4119-9453-aaa922259eb7) does not have Network Contributor role on vnet '" + vnetID + "'.",
|
||||
},
|
||||
{
|
||||
name: "fail: not found",
|
||||
mocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, resourceProvider, "", resourceType, vnetName).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
cancel()
|
||||
}).
|
||||
Return(
|
||||
nil,
|
||||
autorest.DetailedError{
|
||||
StatusCode: http.StatusNotFound,
|
||||
},
|
||||
)
|
||||
},
|
||||
wantErr: "400: InvalidLinkedVNet: : The vnet '" + vnetID + "' could not be found.",
|
||||
},
|
||||
{
|
||||
name: "fail: fp/sp has no permission on the target vnet (forbidden error)",
|
||||
mocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, resourceProvider, "", resourceType, vnetName).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
cancel()
|
||||
}).
|
||||
Return(
|
||||
nil,
|
||||
autorest.DetailedError{
|
||||
StatusCode: http.StatusForbidden,
|
||||
Message: "some forbidden error on the resource.",
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
wantErr: "400: InvalidServicePrincipalPermissions: : The cluster service principal (Application ID: fff51942-b1f9-4119-9453-aaa922259eb7) does not have Network Contributor role on vnet '" + vnetID + "'.\nOriginal error message: some forbidden error on the resource.",
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
permissionsClient := mock_authorization.NewMockPermissionsClient(controller)
|
||||
tt.mocks(permissionsClient, cancel)
|
||||
|
||||
dv := &dynamic{
|
||||
appID: "fff51942-b1f9-4119-9453-aaa922259eb7",
|
||||
authorizerType: AuthorizerClusterServicePrincipal,
|
||||
log: logrus.NewEntry(logrus.StandardLogger()),
|
||||
permissions: permissionsClient,
|
||||
}
|
||||
|
||||
vnetr, err := azure.ParseResourceID(vnetID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dv.validateVnetPermissions(ctx, vnetr)
|
||||
utilerror.AssertErrorMessage(t, err, tt.wantErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRouteTableID(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
|
@ -272,324 +152,6 @@ func TestGetNatGatewayID(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateRouteTablesPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
subnet Subnet
|
||||
permissionMocks func(*mock_authorization.MockPermissionsClient, context.CancelFunc)
|
||||
vnetMocks func(*mock_network.MockVirtualNetworksClient, mgmtnetwork.VirtualNetwork)
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "fail: failed to get vnet",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, errors.New("failed to get vnet"))
|
||||
},
|
||||
wantErr: "failed to get vnet",
|
||||
},
|
||||
{
|
||||
name: "fail: master subnet doesn't exist",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnet.Subnets = nil
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
wantErr: "400: InvalidLinkedVNet: : The provided subnet '" + masterSubnet + "' could not be found.",
|
||||
},
|
||||
{
|
||||
name: "fail: worker subnet ID doesn't exist",
|
||||
subnet: Subnet{ID: workerSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
(*vnet.Subnets)[1].ID = to.StringPtr("not valid")
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
wantErr: "400: InvalidLinkedVNet: : The provided subnet '" + workerSubnet + "' could not be found.",
|
||||
},
|
||||
{
|
||||
name: "fail: permissions don't exist",
|
||||
subnet: Subnet{ID: workerSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
permissionMocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, "Microsoft.Network", "", "routeTables", gomock.Any()).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
cancel()
|
||||
}).
|
||||
Return(
|
||||
[]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
},
|
||||
wantErr: "400: InvalidServicePrincipalPermissions: : The cluster service principal does not have Network Contributor role on route table '" + workerRtID + "'.",
|
||||
},
|
||||
{
|
||||
name: "pass",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
permissionMocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, "Microsoft.Network", "", "routeTables", gomock.Any()).
|
||||
AnyTimes().
|
||||
Return([]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{
|
||||
"Microsoft.Network/routeTables/join/action",
|
||||
"Microsoft.Network/routeTables/read",
|
||||
"Microsoft.Network/routeTables/write",
|
||||
},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pass: no route table to check",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
(*vnet.Subnets)[0].RouteTable = nil
|
||||
(*vnet.Subnets)[1].RouteTable = nil
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
permissionsClient := mock_authorization.NewMockPermissionsClient(controller)
|
||||
vnetClient := mock_network.NewMockVirtualNetworksClient(controller)
|
||||
|
||||
vnet := &mgmtnetwork.VirtualNetwork{
|
||||
ID: &vnetID,
|
||||
VirtualNetworkPropertiesFormat: &mgmtnetwork.VirtualNetworkPropertiesFormat{
|
||||
Subnets: &[]mgmtnetwork.Subnet{
|
||||
{
|
||||
ID: &masterSubnet,
|
||||
SubnetPropertiesFormat: &mgmtnetwork.SubnetPropertiesFormat{
|
||||
RouteTable: &mgmtnetwork.RouteTable{
|
||||
ID: &masterRtID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: &workerSubnet,
|
||||
SubnetPropertiesFormat: &mgmtnetwork.SubnetPropertiesFormat{
|
||||
RouteTable: &mgmtnetwork.RouteTable{
|
||||
ID: &workerRtID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dv := &dynamic{
|
||||
authorizerType: AuthorizerClusterServicePrincipal,
|
||||
log: logrus.NewEntry(logrus.StandardLogger()),
|
||||
permissions: permissionsClient,
|
||||
virtualNetworks: vnetClient,
|
||||
}
|
||||
|
||||
if tt.permissionMocks != nil {
|
||||
tt.permissionMocks(permissionsClient, cancel)
|
||||
}
|
||||
|
||||
if tt.vnetMocks != nil {
|
||||
tt.vnetMocks(vnetClient, *vnet)
|
||||
}
|
||||
|
||||
err := dv.validateRouteTablePermissions(ctx, tt.subnet)
|
||||
utilerror.AssertErrorMessage(t, err, tt.wantErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateNatGatewaysPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
subnet Subnet
|
||||
permissionMocks func(*mock_authorization.MockPermissionsClient, context.CancelFunc)
|
||||
vnetMocks func(*mock_network.MockVirtualNetworksClient, mgmtnetwork.VirtualNetwork)
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "fail: failed to get vnet",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, errors.New("failed to get vnet"))
|
||||
},
|
||||
wantErr: "failed to get vnet",
|
||||
},
|
||||
{
|
||||
name: "fail: master subnet doesn't exist",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnet.Subnets = nil
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
wantErr: "400: InvalidLinkedVNet: : The provided subnet '" + masterSubnet + "' could not be found.",
|
||||
},
|
||||
{
|
||||
name: "fail: worker subnet ID doesn't exist",
|
||||
subnet: Subnet{ID: workerSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
(*vnet.Subnets)[1].ID = to.StringPtr("not valid")
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
wantErr: "400: InvalidLinkedVNet: : The provided subnet '" + workerSubnet + "' could not be found.",
|
||||
},
|
||||
{
|
||||
name: "fail: permissions don't exist",
|
||||
subnet: Subnet{ID: workerSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
permissionMocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, "Microsoft.Network", "", "natGateways", gomock.Any()).
|
||||
Do(func(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) {
|
||||
cancel()
|
||||
}).
|
||||
Return(
|
||||
[]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
)
|
||||
},
|
||||
wantErr: "400: InvalidServicePrincipalPermissions: : The cluster service principal does not have Network Contributor role on nat gateway '" + workerNgID + "'.",
|
||||
},
|
||||
{
|
||||
name: "pass",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
permissionMocks: func(permissionsClient *mock_authorization.MockPermissionsClient, cancel context.CancelFunc) {
|
||||
permissionsClient.EXPECT().
|
||||
ListForResource(gomock.Any(), resourceGroupName, "Microsoft.Network", "", "natGateways", gomock.Any()).
|
||||
AnyTimes().
|
||||
Return([]mgmtauthorization.Permission{
|
||||
{
|
||||
Actions: &[]string{
|
||||
"Microsoft.Network/natGateways/join/action",
|
||||
"Microsoft.Network/natGateways/read",
|
||||
"Microsoft.Network/natGateways/write",
|
||||
},
|
||||
NotActions: &[]string{},
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "pass: no nat gateway to check",
|
||||
subnet: Subnet{ID: masterSubnet},
|
||||
vnetMocks: func(vnetClient *mock_network.MockVirtualNetworksClient, vnet mgmtnetwork.VirtualNetwork) {
|
||||
(*vnet.Subnets)[0].NatGateway = nil
|
||||
(*vnet.Subnets)[1].NatGateway = nil
|
||||
vnetClient.EXPECT().
|
||||
Get(gomock.Any(), resourceGroupName, vnetName, "").
|
||||
Return(vnet, nil)
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
permissionsClient := mock_authorization.NewMockPermissionsClient(controller)
|
||||
vnetClient := mock_network.NewMockVirtualNetworksClient(controller)
|
||||
|
||||
vnet := &mgmtnetwork.VirtualNetwork{
|
||||
ID: &vnetID,
|
||||
VirtualNetworkPropertiesFormat: &mgmtnetwork.VirtualNetworkPropertiesFormat{
|
||||
Subnets: &[]mgmtnetwork.Subnet{
|
||||
{
|
||||
ID: &masterSubnet,
|
||||
SubnetPropertiesFormat: &mgmtnetwork.SubnetPropertiesFormat{
|
||||
NatGateway: &mgmtnetwork.SubResource{
|
||||
ID: &masterNgID,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: &workerSubnet,
|
||||
SubnetPropertiesFormat: &mgmtnetwork.SubnetPropertiesFormat{
|
||||
NatGateway: &mgmtnetwork.SubResource{
|
||||
ID: &workerNgID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dv := &dynamic{
|
||||
authorizerType: AuthorizerClusterServicePrincipal,
|
||||
log: logrus.NewEntry(logrus.StandardLogger()),
|
||||
permissions: permissionsClient,
|
||||
virtualNetworks: vnetClient,
|
||||
}
|
||||
|
||||
if tt.permissionMocks != nil {
|
||||
tt.permissionMocks(permissionsClient, cancel)
|
||||
}
|
||||
|
||||
if tt.vnetMocks != nil {
|
||||
tt.vnetMocks(vnetClient, *vnet)
|
||||
}
|
||||
|
||||
err := dv.validateNatGatewayPermissions(ctx, tt.subnet)
|
||||
utilerror.AssertErrorMessage(t, err, tt.wantErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCIDRRanges(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
|
@ -1131,7 +693,7 @@ func mockTokenCredential(tokenCred *mock_azcore.MockTokenCredential) {
|
|||
Return(mockAccessToken, nil)
|
||||
}
|
||||
|
||||
func TestValidateVnetPermissionsWithCheckAccess(t *testing.T) {
|
||||
func TestValidateVnetPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range []struct {
|
||||
|
@ -1289,7 +851,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func TestValidateRouteTablesPermissionsWithCheckAccess(t *testing.T) {
|
||||
func TestValidateRouteTablesPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range []struct {
|
||||
|
@ -1504,7 +1066,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func TestValidateNatGatewaysPermissionsWithCheckAccess(t *testing.T) {
|
||||
func TestValidateNatGatewaysPermissions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range []struct {
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
"github.com/Azure/ARO-RP/pkg/api"
|
||||
"github.com/Azure/ARO-RP/pkg/env"
|
||||
"github.com/Azure/ARO-RP/pkg/util/azureclient/authz/remotepdp"
|
||||
"github.com/Azure/ARO-RP/pkg/util/feature"
|
||||
"github.com/Azure/ARO-RP/pkg/validate/dynamic"
|
||||
)
|
||||
|
||||
|
@ -134,20 +133,12 @@ func (dv *openShiftClusterDynamicValidator) Dynamic(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if useCheckAccess || feature.IsRegisteredForFeature(
|
||||
dv.subscriptionDoc.Subscription.Properties,
|
||||
api.FeatureFlagCheckAccessTestToggle,
|
||||
) {
|
||||
// TODO remove after successfully migrating to CheckAccess
|
||||
dv.log.Info("Using CheckAccess instead of ListPermissions")
|
||||
|
||||
aroEnv := dv.env.Environment()
|
||||
pdpClient = remotepdp.NewRemotePDPClient(
|
||||
fmt.Sprintf(aroEnv.Endpoint, dv.env.Location()),
|
||||
aroEnv.OAuthScope,
|
||||
fpClientCred,
|
||||
)
|
||||
}
|
||||
aroEnv := dv.env.Environment()
|
||||
pdpClient = remotepdp.NewRemotePDPClient(
|
||||
fmt.Sprintf(aroEnv.Endpoint, dv.env.Location()),
|
||||
aroEnv.OAuthScope,
|
||||
fpClientCred,
|
||||
)
|
||||
|
||||
scopes := []string{dv.env.Environment().ResourceManagerScope}
|
||||
err = ensureAccessTokenClaims(ctx, spClientCred, scopes)
|
||||
|
|
|
@ -18,59 +18,110 @@ type hookFunc func(obj client.Object) error
|
|||
type HookingClient struct {
|
||||
f client.WithWatch
|
||||
|
||||
getHook []getFunc
|
||||
deleteHook []hookFunc
|
||||
createHook []hookFunc
|
||||
updateHook []hookFunc
|
||||
patchHook []hookFunc
|
||||
preGetHook []getFunc
|
||||
preDeleteHook []hookFunc
|
||||
preCreateHook []hookFunc
|
||||
preUpdateHook []hookFunc
|
||||
prePatchHook []hookFunc
|
||||
|
||||
postGetHook []getFunc
|
||||
postDeleteHook []hookFunc
|
||||
postCreateHook []hookFunc
|
||||
postUpdateHook []hookFunc
|
||||
postPatchHook []hookFunc
|
||||
}
|
||||
|
||||
var _ client.Client = &HookingClient{}
|
||||
|
||||
// NewHookingClient creates a
|
||||
// NewHookingClient creates a client which allows hooks to be added before and
|
||||
// after the client event. Errors returned in the hooks are returned to the
|
||||
// caller directly, to simulate issues such as disconnections or errors.
|
||||
// Prehooks that cause errors will cause the underlying wrapped client to not be
|
||||
// called.
|
||||
func NewHookingClient(c client.WithWatch) *HookingClient {
|
||||
return &HookingClient{
|
||||
f: c,
|
||||
getHook: []getFunc{},
|
||||
deleteHook: []hookFunc{},
|
||||
createHook: []hookFunc{},
|
||||
updateHook: []hookFunc{},
|
||||
patchHook: []hookFunc{},
|
||||
f: c,
|
||||
preGetHook: []getFunc{},
|
||||
preDeleteHook: []hookFunc{},
|
||||
preCreateHook: []hookFunc{},
|
||||
preUpdateHook: []hookFunc{},
|
||||
prePatchHook: []hookFunc{},
|
||||
|
||||
postGetHook: []getFunc{},
|
||||
postDeleteHook: []hookFunc{},
|
||||
postCreateHook: []hookFunc{},
|
||||
postUpdateHook: []hookFunc{},
|
||||
postPatchHook: []hookFunc{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithGetHook(f getFunc) *HookingClient {
|
||||
c.getHook = append(c.getHook, f)
|
||||
c.postGetHook = append(c.postGetHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithDeleteHook(f hookFunc) *HookingClient {
|
||||
c.deleteHook = append(c.deleteHook, f)
|
||||
c.postDeleteHook = append(c.postDeleteHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithCreateHook(f hookFunc) *HookingClient {
|
||||
c.createHook = append(c.createHook, f)
|
||||
c.postCreateHook = append(c.postCreateHook, f)
|
||||
return c
|
||||
}
|
||||
func (c *HookingClient) WithUpdateHook(f hookFunc) *HookingClient {
|
||||
c.updateHook = append(c.updateHook, f)
|
||||
c.postUpdateHook = append(c.postUpdateHook, f)
|
||||
return c
|
||||
}
|
||||
func (c *HookingClient) WithPatchHook(f hookFunc) *HookingClient {
|
||||
c.patchHook = append(c.patchHook, f)
|
||||
c.postPatchHook = append(c.postPatchHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithPreGetHook(f getFunc) *HookingClient {
|
||||
c.preGetHook = append(c.preGetHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithPreDeleteHook(f hookFunc) *HookingClient {
|
||||
c.preDeleteHook = append(c.preDeleteHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *HookingClient) WithPreCreateHook(f hookFunc) *HookingClient {
|
||||
c.preCreateHook = append(c.preCreateHook, f)
|
||||
return c
|
||||
}
|
||||
func (c *HookingClient) WithPreUpdateHook(f hookFunc) *HookingClient {
|
||||
c.preUpdateHook = append(c.preUpdateHook, f)
|
||||
return c
|
||||
}
|
||||
func (c *HookingClient) WithPrePatchHook(f hookFunc) *HookingClient {
|
||||
c.prePatchHook = append(c.prePatchHook, f)
|
||||
return c
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Reader.Get]
|
||||
func (c *HookingClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
for _, h := range c.getHook {
|
||||
for _, h := range c.preGetHook {
|
||||
err := h(key, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.f.Get(ctx, key, obj)
|
||||
|
||||
err := c.f.Get(ctx, key, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range c.postGetHook {
|
||||
err := h(key, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Reader.List]
|
||||
|
@ -85,24 +136,48 @@ func (c *HookingClient) Watch(ctx context.Context, list client.ObjectList, opts
|
|||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Writer.Create]
|
||||
func (c *HookingClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
|
||||
for _, h := range c.createHook {
|
||||
for _, h := range c.preCreateHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.f.Create(ctx, obj, opts...)
|
||||
|
||||
err := c.f.Create(ctx, obj, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range c.postCreateHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Writer.Delete]
|
||||
func (c *HookingClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
|
||||
for _, h := range c.deleteHook {
|
||||
for _, h := range c.preDeleteHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.f.Delete(ctx, obj, opts...)
|
||||
|
||||
err := c.f.Delete(ctx, obj, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range c.postDeleteHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Writer.DeleteAllOf]
|
||||
|
@ -112,24 +187,48 @@ func (c *HookingClient) DeleteAllOf(ctx context.Context, obj client.Object, opts
|
|||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Writer.Update]
|
||||
func (c *HookingClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
|
||||
for _, h := range c.updateHook {
|
||||
for _, h := range c.preUpdateHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.f.Update(ctx, obj, opts...)
|
||||
|
||||
err := c.f.Update(ctx, obj, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range c.postUpdateHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Writer.Patch]
|
||||
func (c *HookingClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
for _, h := range c.patchHook {
|
||||
for _, h := range c.prePatchHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.f.Patch(ctx, obj, patch, opts...)
|
||||
|
||||
err := c.f.Patch(ctx, obj, patch, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range c.postPatchHook {
|
||||
err := h(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/client.Client.Scheme]
|
||||
|
|
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/doc.go
сгенерированный
поставляемый
Normal file
9
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/doc.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,9 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright 2017 Microsoft Corporation. All rights reserved.
|
||||
// Use of this source code is governed by an MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package to contains various type-conversion helper functions.
|
||||
package to
|
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/to.go
сгенерированный
поставляемый
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/to/to.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,21 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package to
|
||||
|
||||
// Ptr returns a pointer to the provided value.
|
||||
func Ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// SliceOfPtrs returns a slice of *T from the specified values.
|
||||
func SliceOfPtrs[T any](vv ...T) []*T {
|
||||
slc := make([]*T, len(vv))
|
||||
for i := range vv {
|
||||
slc[i] = Ptr(vv[i])
|
||||
}
|
||||
return slc
|
||||
}
|
43
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
сгенерированный
поставляемый
43
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
сгенерированный
поставляемый
|
@ -1,10 +1,53 @@
|
|||
# Release History
|
||||
|
||||
## 1.4.0 (2023-10-10)
|
||||
|
||||
### Bugs Fixed
|
||||
* `ManagedIdentityCredential` will now retry when IMDS responds 410 or 503
|
||||
|
||||
## 1.4.0-beta.5 (2023-09-12)
|
||||
|
||||
### Features Added
|
||||
* Service principal credentials can request CAE tokens
|
||||
|
||||
### Breaking Changes
|
||||
> These changes affect only code written against a beta version such as v1.4.0-beta.4
|
||||
* Whether `GetToken` requests a CAE token is now determined by `TokenRequestOptions.EnableCAE`. Azure
|
||||
SDK clients which support CAE will set this option automatically. Credentials no longer request CAE
|
||||
tokens by default or observe the environment variable "AZURE_IDENTITY_DISABLE_CP1".
|
||||
|
||||
### Bugs Fixed
|
||||
* Credential chains such as `DefaultAzureCredential` now try their next credential, if any, when
|
||||
managed identity authentication fails in a Docker Desktop container
|
||||
([#21417](https://github.com/Azure/azure-sdk-for-go/issues/21417))
|
||||
|
||||
## 1.4.0-beta.4 (2023-08-16)
|
||||
|
||||
### Other Changes
|
||||
* Upgraded dependencies
|
||||
|
||||
## 1.3.1 (2023-08-16)
|
||||
|
||||
### Other Changes
|
||||
* Upgraded dependencies
|
||||
|
||||
## 1.4.0-beta.3 (2023-08-08)
|
||||
|
||||
### Bugs Fixed
|
||||
* One invocation of `AzureCLICredential.GetToken()` and `OnBehalfOfCredential.GetToken()`
|
||||
can no longer make two authentication attempts
|
||||
|
||||
## 1.4.0-beta.2 (2023-07-14)
|
||||
|
||||
### Other Changes
|
||||
* `DefaultAzureCredentialOptions.TenantID` applies to workload identity authentication
|
||||
* Upgraded dependencies
|
||||
|
||||
## 1.4.0-beta.1 (2023-06-06)
|
||||
|
||||
### Other Changes
|
||||
* Re-enabled CAE support as in v1.3.0-beta.3
|
||||
|
||||
## 1.3.0 (2023-05-09)
|
||||
|
||||
### Breaking Changes
|
||||
|
|
2
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
сгенерированный
поставляемый
2
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
сгенерированный
поставляемый
|
@ -76,12 +76,14 @@ azlog.SetListener(func(event azlog.Event, s string) {
|
|||
azlog.SetEvents(azidentity.EventAuthentication)
|
||||
```
|
||||
|
||||
<a id="dac"></a>
|
||||
## Troubleshoot DefaultAzureCredential authentication issues
|
||||
|
||||
| Error |Description| Mitigation |
|
||||
|---|---|---|
|
||||
|"DefaultAzureCredential failed to acquire a token"|No credential in the `DefaultAzureCredential` chain provided a token|<ul><li>[Enable logging](#enable-and-configure-logging) to get further diagnostic information.</li><li>Consult the troubleshooting guide for underlying credential types for more information.</li><ul><li>[EnvironmentCredential](#troubleshoot-environmentcredential-authentication-issues)</li><li>[ManagedIdentityCredential](#troubleshoot-managedidentitycredential-authentication-issues)</li><li>[AzureCLICredential](#troubleshoot-azureclicredential-authentication-issues)</li></ul>|
|
||||
|Error from the client with a status code of 401 or 403|Authentication succeeded but the authorizing Azure service responded with a 401 (Unauthorized), or 403 (Forbidden) status code|<ul><li>[Enable logging](#enable-and-configure-logging) to determine which credential in the chain returned the authenticating token.</li><li>If an unexpected credential is returning a token, check application configuration such as environment variables.</li><li>Ensure the correct role is assigned to the authenticated identity. For example, a service specific role rather than the subscription Owner role.</li></ul>|
|
||||
|"managed identity timed out"|`DefaultAzureCredential` sets a short timeout on its first managed identity authentication attempt to prevent very long timeouts during local development when no managed identity is available. That timeout causes this error in production when an application requests a token before the hosting environment is ready to provide one.|Use [ManagedIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ManagedIdentityCredential) directly, at least in production. It doesn't set a timeout on its authentication attempts.|
|
||||
|
||||
## Troubleshoot EnvironmentCredential authentication issues
|
||||
|
||||
|
|
98
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go
сгенерированный
поставляемый
98
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go
сгенерированный
поставляемый
|
@ -10,12 +10,12 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
|
||||
|
@ -41,65 +41,18 @@ const (
|
|||
organizationsTenantID = "organizations"
|
||||
developerSignOnClientID = "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
|
||||
defaultSuffix = "/.default"
|
||||
tenantIDValidationErr = "invalid tenantID. You can locate your tenantID by following the instructions listed here: https://docs.microsoft.com/partner-center/find-ids-and-domain-names"
|
||||
)
|
||||
|
||||
var (
|
||||
// capability CP1 indicates the client application is capable of handling CAE claims challenges
|
||||
cp1 = []string{"CP1"}
|
||||
// CP1 is disabled until CAE support is added back
|
||||
disableCP1 = true
|
||||
cp1 = []string{"CP1"}
|
||||
errInvalidTenantID = errors.New("invalid tenantID. You can locate your tenantID by following the instructions listed here: https://learn.microsoft.com/partner-center/find-ids-and-domain-names")
|
||||
)
|
||||
|
||||
var getConfidentialClient = func(clientID, tenantID string, cred confidential.Credential, co *azcore.ClientOptions, additionalOpts ...confidential.Option) (confidentialClient, error) {
|
||||
if !validTenantID(tenantID) {
|
||||
return confidential.Client{}, errors.New(tenantIDValidationErr)
|
||||
}
|
||||
authorityHost, err := setAuthorityHost(co.Cloud)
|
||||
if err != nil {
|
||||
return confidential.Client{}, err
|
||||
}
|
||||
authority := runtime.JoinPaths(authorityHost, tenantID)
|
||||
o := []confidential.Option{
|
||||
confidential.WithAzureRegion(os.Getenv(azureRegionalAuthorityName)),
|
||||
confidential.WithHTTPClient(newPipelineAdapter(co)),
|
||||
}
|
||||
if !disableCP1 {
|
||||
o = append(o, confidential.WithClientCapabilities(cp1))
|
||||
}
|
||||
o = append(o, additionalOpts...)
|
||||
if strings.ToLower(tenantID) == "adfs" {
|
||||
o = append(o, confidential.WithInstanceDiscovery(false))
|
||||
}
|
||||
return confidential.New(authority, clientID, cred, o...)
|
||||
}
|
||||
|
||||
var getPublicClient = func(clientID, tenantID string, co *azcore.ClientOptions, additionalOpts ...public.Option) (public.Client, error) {
|
||||
if !validTenantID(tenantID) {
|
||||
return public.Client{}, errors.New(tenantIDValidationErr)
|
||||
}
|
||||
authorityHost, err := setAuthorityHost(co.Cloud)
|
||||
if err != nil {
|
||||
return public.Client{}, err
|
||||
}
|
||||
o := []public.Option{
|
||||
public.WithAuthority(runtime.JoinPaths(authorityHost, tenantID)),
|
||||
public.WithHTTPClient(newPipelineAdapter(co)),
|
||||
}
|
||||
if !disableCP1 {
|
||||
o = append(o, public.WithClientCapabilities(cp1))
|
||||
}
|
||||
o = append(o, additionalOpts...)
|
||||
if strings.ToLower(tenantID) == "adfs" {
|
||||
o = append(o, public.WithInstanceDiscovery(false))
|
||||
}
|
||||
return public.New(clientID, o...)
|
||||
}
|
||||
|
||||
// setAuthorityHost initializes the authority host for credentials. Precedence is:
|
||||
// 1. cloud.Configuration.ActiveDirectoryAuthorityHost value set by user
|
||||
// 2. value of AZURE_AUTHORITY_HOST
|
||||
// 3. default: Azure Public Cloud
|
||||
// 1. cloud.Configuration.ActiveDirectoryAuthorityHost value set by user
|
||||
// 2. value of AZURE_AUTHORITY_HOST
|
||||
// 3. default: Azure Public Cloud
|
||||
func setAuthorityHost(cc cloud.Configuration) (string, error) {
|
||||
host := cc.ActiveDirectoryAuthorityHost
|
||||
if host == "" {
|
||||
|
@ -121,6 +74,41 @@ func setAuthorityHost(cc cloud.Configuration) (string, error) {
|
|||
return host, nil
|
||||
}
|
||||
|
||||
// resolveAdditionalTenants returns a copy of tenants, simplified when tenants contains a wildcard
|
||||
func resolveAdditionalTenants(tenants []string) []string {
|
||||
if len(tenants) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, t := range tenants {
|
||||
// a wildcard makes all other values redundant
|
||||
if t == "*" {
|
||||
return []string{"*"}
|
||||
}
|
||||
}
|
||||
cp := make([]string, len(tenants))
|
||||
copy(cp, tenants)
|
||||
return cp
|
||||
}
|
||||
|
||||
// resolveTenant returns the correct tenant for a token request
|
||||
func resolveTenant(defaultTenant, specified, credName string, additionalTenants []string) (string, error) {
|
||||
if specified == "" || specified == defaultTenant {
|
||||
return defaultTenant, nil
|
||||
}
|
||||
if defaultTenant == "adfs" {
|
||||
return "", errors.New("ADFS doesn't support tenants")
|
||||
}
|
||||
if !validTenantID(specified) {
|
||||
return "", errInvalidTenantID
|
||||
}
|
||||
for _, t := range additionalTenants {
|
||||
if t == "*" || t == specified {
|
||||
return specified, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf(`%s isn't configured to acquire tokens for tenant %q. To enable acquiring tokens for this tenant add it to the AdditionallyAllowedTenants on the credential options, or add "*" to allow acquiring tokens for any tenant`, credName, specified)
|
||||
}
|
||||
|
||||
// validTenantID return true is it receives a valid tenantID, returns false otherwise
|
||||
func validTenantID(tenantID string) bool {
|
||||
match, err := regexp.MatchString("^[0-9a-zA-Z-.]+$", tenantID)
|
||||
|
@ -173,7 +161,7 @@ func (p pipelineAdapter) Do(r *http.Request) (*http.Response, error) {
|
|||
}
|
||||
|
||||
// enables fakes for test scenarios
|
||||
type confidentialClient interface {
|
||||
type msalConfidentialClient interface {
|
||||
AcquireTokenSilent(ctx context.Context, scopes []string, options ...confidential.AcquireSilentOption) (confidential.AuthResult, error)
|
||||
AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, options ...confidential.AcquireByAuthCodeOption) (confidential.AuthResult, error)
|
||||
AcquireTokenByCredential(ctx context.Context, scopes []string, options ...confidential.AcquireByCredentialOption) (confidential.AuthResult, error)
|
||||
|
@ -181,7 +169,7 @@ type confidentialClient interface {
|
|||
}
|
||||
|
||||
// enables fakes for test scenarios
|
||||
type publicClient interface {
|
||||
type msalPublicClient interface {
|
||||
AcquireTokenSilent(ctx context.Context, scopes []string, options ...public.AcquireSilentOption) (public.AuthResult, error)
|
||||
AcquireTokenByUsernamePassword(ctx context.Context, scopes []string, username string, password string, options ...public.AcquireByUsernamePasswordOption) (public.AuthResult, error)
|
||||
AcquireTokenByDeviceCode(ctx context.Context, scopes []string, options ...public.AcquireByDeviceCodeOption) (public.DeviceCode, error)
|
||||
|
|
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go
сгенерированный
поставляемый
129
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_cli_credential.go
сгенерированный
поставляемый
|
@ -17,10 +17,12 @@ import (
|
|||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -47,14 +49,14 @@ type AzureCLICredentialOptions struct {
|
|||
// init returns an instance of AzureCLICredentialOptions initialized with default values.
|
||||
func (o *AzureCLICredentialOptions) init() {
|
||||
if o.tokenProvider == nil {
|
||||
o.tokenProvider = defaultTokenProvider()
|
||||
o.tokenProvider = defaultTokenProvider
|
||||
}
|
||||
}
|
||||
|
||||
// AzureCLICredential authenticates as the identity logged in to the Azure CLI.
|
||||
type AzureCLICredential struct {
|
||||
s *syncer
|
||||
tokenProvider azureCLITokenProvider
|
||||
mu *sync.Mutex
|
||||
opts AzureCLICredentialOptions
|
||||
}
|
||||
|
||||
// NewAzureCLICredential constructs an AzureCLICredential. Pass nil to accept default options.
|
||||
|
@ -64,9 +66,8 @@ func NewAzureCLICredential(options *AzureCLICredentialOptions) (*AzureCLICredent
|
|||
cp = *options
|
||||
}
|
||||
cp.init()
|
||||
c := AzureCLICredential{tokenProvider: cp.tokenProvider}
|
||||
c.s = newSyncer(credNameAzureCLI, cp.TenantID, cp.AdditionallyAllowedTenants, c.requestToken, c.requestToken)
|
||||
return &c, nil
|
||||
cp.AdditionallyAllowedTenants = resolveAdditionalTenants(cp.AdditionallyAllowedTenants)
|
||||
return &AzureCLICredential{mu: &sync.Mutex{}, opts: cp}, nil
|
||||
}
|
||||
|
||||
// GetToken requests a token from the Azure CLI. This credential doesn't cache tokens, so every call invokes the CLI.
|
||||
|
@ -75,13 +76,15 @@ func (c *AzureCLICredential) GetToken(ctx context.Context, opts policy.TokenRequ
|
|||
if len(opts.Scopes) != 1 {
|
||||
return azcore.AccessToken{}, errors.New(credNameAzureCLI + ": GetToken() requires exactly one scope")
|
||||
}
|
||||
// CLI expects an AAD v1 resource, not a v2 scope
|
||||
tenant, err := resolveTenant(c.opts.TenantID, opts.TenantID, credNameAzureCLI, c.opts.AdditionallyAllowedTenants)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
// pass the CLI an AAD v1 resource because we don't know which CLI version is installed and older ones don't support v2 scopes
|
||||
opts.Scopes = []string{strings.TrimSuffix(opts.Scopes[0], defaultSuffix)}
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *AzureCLICredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
b, err := c.tokenProvider(ctx, opts.Scopes[0], opts.TenantID)
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
b, err := c.opts.tokenProvider(ctx, opts.Scopes[0], tenant)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
|
@ -89,61 +92,61 @@ func (c *AzureCLICredential) requestToken(ctx context.Context, opts policy.Token
|
|||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", credNameAzureCLI, strings.Join(opts.Scopes, ", "))
|
||||
log.Write(EventAuthentication, msg)
|
||||
return at, nil
|
||||
}
|
||||
|
||||
func defaultTokenProvider() func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
|
||||
return func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
|
||||
match, err := regexp.MatchString("^[0-9a-zA-Z-.:/]+$", resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf(`%s: unexpected scope "%s". Only alphanumeric characters and ".", ";", "-", and "/" are allowed`, credNameAzureCLI, resource)
|
||||
}
|
||||
|
||||
// set a default timeout for this authentication iff the application hasn't done so already
|
||||
var cancel context.CancelFunc
|
||||
if _, hasDeadline := ctx.Deadline(); !hasDeadline {
|
||||
ctx, cancel = context.WithTimeout(ctx, timeoutCLIRequest)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
commandLine := "az account get-access-token -o json --resource " + resource
|
||||
if tenantID != "" {
|
||||
commandLine += " --tenant " + tenantID
|
||||
}
|
||||
var cliCmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
dir := os.Getenv("SYSTEMROOT")
|
||||
if dir == "" {
|
||||
return nil, newCredentialUnavailableError(credNameAzureCLI, "environment variable 'SYSTEMROOT' has no value")
|
||||
}
|
||||
cliCmd = exec.CommandContext(ctx, "cmd.exe", "/c", commandLine)
|
||||
cliCmd.Dir = dir
|
||||
} else {
|
||||
cliCmd = exec.CommandContext(ctx, "/bin/sh", "-c", commandLine)
|
||||
cliCmd.Dir = "/bin"
|
||||
}
|
||||
cliCmd.Env = os.Environ()
|
||||
var stderr bytes.Buffer
|
||||
cliCmd.Stderr = &stderr
|
||||
|
||||
output, err := cliCmd.Output()
|
||||
if err != nil {
|
||||
msg := stderr.String()
|
||||
var exErr *exec.ExitError
|
||||
if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.HasPrefix(msg, "'az' is not recognized") {
|
||||
msg = "Azure CLI not found on path"
|
||||
}
|
||||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return nil, newCredentialUnavailableError(credNameAzureCLI, msg)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
var defaultTokenProvider azureCLITokenProvider = func(ctx context.Context, resource string, tenantID string) ([]byte, error) {
|
||||
match, err := regexp.MatchString("^[0-9a-zA-Z-.:/]+$", resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf(`%s: unexpected scope "%s". Only alphanumeric characters and ".", ";", "-", and "/" are allowed`, credNameAzureCLI, resource)
|
||||
}
|
||||
|
||||
// set a default timeout for this authentication iff the application hasn't done so already
|
||||
var cancel context.CancelFunc
|
||||
if _, hasDeadline := ctx.Deadline(); !hasDeadline {
|
||||
ctx, cancel = context.WithTimeout(ctx, timeoutCLIRequest)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
commandLine := "az account get-access-token -o json --resource " + resource
|
||||
if tenantID != "" {
|
||||
commandLine += " --tenant " + tenantID
|
||||
}
|
||||
var cliCmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
dir := os.Getenv("SYSTEMROOT")
|
||||
if dir == "" {
|
||||
return nil, newCredentialUnavailableError(credNameAzureCLI, "environment variable 'SYSTEMROOT' has no value")
|
||||
}
|
||||
cliCmd = exec.CommandContext(ctx, "cmd.exe", "/c", commandLine)
|
||||
cliCmd.Dir = dir
|
||||
} else {
|
||||
cliCmd = exec.CommandContext(ctx, "/bin/sh", "-c", commandLine)
|
||||
cliCmd.Dir = "/bin"
|
||||
}
|
||||
cliCmd.Env = os.Environ()
|
||||
var stderr bytes.Buffer
|
||||
cliCmd.Stderr = &stderr
|
||||
|
||||
output, err := cliCmd.Output()
|
||||
if err != nil {
|
||||
msg := stderr.String()
|
||||
var exErr *exec.ExitError
|
||||
if errors.As(err, &exErr) && exErr.ExitCode() == 127 || strings.HasPrefix(msg, "'az' is not recognized") {
|
||||
msg = "Azure CLI not found on path"
|
||||
}
|
||||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return nil, newCredentialUnavailableError(credNameAzureCLI, msg)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (c *AzureCLICredential) createAccessToken(tk []byte) (azcore.AccessToken, error) {
|
||||
|
|
|
@ -26,22 +26,9 @@ stages:
|
|||
parameters:
|
||||
RunLiveTests: true
|
||||
ServiceDirectory: 'azidentity'
|
||||
PreSteps:
|
||||
- pwsh: |
|
||||
[System.Convert]::FromBase64String($env:PFX_CONTENTS) | Set-Content -Path $(Agent.TempDirectory)/test.pfx -AsByteStream
|
||||
Set-Content -Path $(Agent.TempDirectory)/test.pem -Value $env:PEM_CONTENTS
|
||||
[System.Convert]::FromBase64String($env:SNI_CONTENTS) | Set-Content -Path $(Agent.TempDirectory)/testsni.pfx -AsByteStream
|
||||
env:
|
||||
PFX_CONTENTS: $(net-identity-spcert-pfx)
|
||||
PEM_CONTENTS: $(net-identity-spcert-pem)
|
||||
SNI_CONTENTS: $(net-identity-spcert-sni)
|
||||
EnvVars:
|
||||
AZURE_IDENTITY_TEST_TENANTID: $(net-identity-tenantid)
|
||||
AZURE_IDENTITY_TEST_USERNAME: $(net-identity-username)
|
||||
AZURE_IDENTITY_TEST_PASSWORD: $(net-identity-password)
|
||||
IDENTITY_SP_TENANT_ID: $(net-identity-sp-tenantid)
|
||||
IDENTITY_SP_CLIENT_ID: $(net-identity-sp-clientid)
|
||||
IDENTITY_SP_CLIENT_SECRET: $(net-identity-sp-clientsecret)
|
||||
IDENTITY_SP_CERT_PEM: $(Agent.TempDirectory)/test.pem
|
||||
IDENTITY_SP_CERT_PFX: $(Agent.TempDirectory)/test.pfx
|
||||
IDENTITY_SP_CERT_SNI: $(Agent.TempDirectory)/testsni.pfx
|
||||
CloudConfig:
|
||||
Public:
|
||||
SubscriptionConfigurations:
|
||||
- $(sub-config-azure-cloud-test-resources)
|
||||
# Contains alternate tenant, AAD app and cert info for testing
|
||||
- $(sub-config-identity-test-resources)
|
||||
|
|
26
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go
сгенерированный
поставляемый
26
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go
сгенерированный
поставляемый
|
@ -24,8 +24,7 @@ const credNameAssertion = "ClientAssertionCredential"
|
|||
//
|
||||
// [Azure AD documentation]: https://docs.microsoft.com/azure/active-directory/develop/active-directory-certificate-credentials#assertion-format
|
||||
type ClientAssertionCredential struct {
|
||||
client confidentialClient
|
||||
s *syncer
|
||||
client *confidentialClient
|
||||
}
|
||||
|
||||
// ClientAssertionCredentialOptions contains optional parameters for ClientAssertionCredential.
|
||||
|
@ -56,28 +55,21 @@ func NewClientAssertionCredential(tenantID, clientID string, getAssertion func(c
|
|||
return getAssertion(ctx)
|
||||
},
|
||||
)
|
||||
c, err := getConfidentialClient(clientID, tenantID, cred, &options.ClientOptions, confidential.WithInstanceDiscovery(!options.DisableInstanceDiscovery))
|
||||
msalOpts := confidentialClientOptions{
|
||||
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
}
|
||||
c, err := newConfidentialClient(tenantID, clientID, credNameAssertion, cred, msalOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cac := ClientAssertionCredential{client: c}
|
||||
cac.s = newSyncer(credNameAssertion, tenantID, options.AdditionallyAllowedTenants, cac.requestToken, cac.silentAuth)
|
||||
return &cac, nil
|
||||
return &ClientAssertionCredential{client: c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (c *ClientAssertionCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *ClientAssertionCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *ClientAssertionCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenByCredential(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*ClientAssertionCredential)(nil)
|
||||
|
|
30
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go
сгенерированный
поставляемый
30
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go
сгенерированный
поставляемый
|
@ -42,8 +42,7 @@ type ClientCertificateCredentialOptions struct {
|
|||
|
||||
// ClientCertificateCredential authenticates a service principal with a certificate.
|
||||
type ClientCertificateCredential struct {
|
||||
client confidentialClient
|
||||
s *syncer
|
||||
client *confidentialClient
|
||||
}
|
||||
|
||||
// NewClientCertificateCredential constructs a ClientCertificateCredential. Pass nil for options to accept defaults.
|
||||
|
@ -58,33 +57,22 @@ func NewClientCertificateCredential(tenantID string, clientID string, certs []*x
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var o []confidential.Option
|
||||
if options.SendCertificateChain {
|
||||
o = append(o, confidential.WithX5C())
|
||||
msalOpts := confidentialClientOptions{
|
||||
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
SendX5C: options.SendCertificateChain,
|
||||
}
|
||||
o = append(o, confidential.WithInstanceDiscovery(!options.DisableInstanceDiscovery))
|
||||
c, err := getConfidentialClient(clientID, tenantID, cred, &options.ClientOptions, o...)
|
||||
c, err := newConfidentialClient(tenantID, clientID, credNameCert, cred, msalOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc := ClientCertificateCredential{client: c}
|
||||
cc.s = newSyncer(credNameCert, tenantID, options.AdditionallyAllowedTenants, cc.requestToken, cc.silentAuth)
|
||||
return &cc, nil
|
||||
return &ClientCertificateCredential{client: c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (c *ClientCertificateCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *ClientCertificateCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *ClientCertificateCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenByCredential(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
// ParseCertificates loads certificates and a private key, in PEM or PKCS12 format, for use with NewClientCertificateCredential.
|
||||
|
|
28
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go
сгенерированный
поставляемый
28
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go
сгенерированный
поставляемый
|
@ -33,8 +33,7 @@ type ClientSecretCredentialOptions struct {
|
|||
|
||||
// ClientSecretCredential authenticates an application with a client secret.
|
||||
type ClientSecretCredential struct {
|
||||
client confidentialClient
|
||||
s *syncer
|
||||
client *confidentialClient
|
||||
}
|
||||
|
||||
// NewClientSecretCredential constructs a ClientSecretCredential. Pass nil for options to accept defaults.
|
||||
|
@ -46,30 +45,21 @@ func NewClientSecretCredential(tenantID string, clientID string, clientSecret st
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := getConfidentialClient(
|
||||
clientID, tenantID, cred, &options.ClientOptions, confidential.WithInstanceDiscovery(!options.DisableInstanceDiscovery),
|
||||
)
|
||||
msalOpts := confidentialClientOptions{
|
||||
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
}
|
||||
c, err := newConfidentialClient(tenantID, clientID, credNameSecret, cred, msalOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csc := ClientSecretCredential{client: c}
|
||||
csc.s = newSyncer(credNameSecret, tenantID, options.AdditionallyAllowedTenants, csc.requestToken, csc.silentAuth)
|
||||
return &csc, nil
|
||||
return &ClientSecretCredential{c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (c *ClientSecretCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *ClientSecretCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *ClientSecretCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenByCredential(ctx, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*ClientSecretCredential)(nil)
|
||||
|
|
156
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go
сгенерированный
поставляемый
Normal file
156
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,156 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azidentity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential"
|
||||
)
|
||||
|
||||
type confidentialClientOptions struct {
|
||||
azcore.ClientOptions
|
||||
|
||||
AdditionallyAllowedTenants []string
|
||||
// Assertion for on-behalf-of authentication
|
||||
Assertion string
|
||||
DisableInstanceDiscovery, SendX5C bool
|
||||
}
|
||||
|
||||
// confidentialClient wraps the MSAL confidential client
|
||||
type confidentialClient struct {
|
||||
cae, noCAE msalConfidentialClient
|
||||
caeMu, noCAEMu, clientMu *sync.Mutex
|
||||
clientID, tenantID string
|
||||
cred confidential.Credential
|
||||
host string
|
||||
name string
|
||||
opts confidentialClientOptions
|
||||
region string
|
||||
}
|
||||
|
||||
func newConfidentialClient(tenantID, clientID, name string, cred confidential.Credential, opts confidentialClientOptions) (*confidentialClient, error) {
|
||||
if !validTenantID(tenantID) {
|
||||
return nil, errInvalidTenantID
|
||||
}
|
||||
host, err := setAuthorityHost(opts.Cloud)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts.AdditionallyAllowedTenants = resolveAdditionalTenants(opts.AdditionallyAllowedTenants)
|
||||
return &confidentialClient{
|
||||
caeMu: &sync.Mutex{},
|
||||
clientID: clientID,
|
||||
clientMu: &sync.Mutex{},
|
||||
cred: cred,
|
||||
host: host,
|
||||
name: name,
|
||||
noCAEMu: &sync.Mutex{},
|
||||
opts: opts,
|
||||
region: os.Getenv(azureRegionalAuthorityName),
|
||||
tenantID: tenantID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from MSAL, checking the cache first.
|
||||
func (c *confidentialClient) GetToken(ctx context.Context, tro policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
if len(tro.Scopes) < 1 {
|
||||
return azcore.AccessToken{}, fmt.Errorf("%s.GetToken() requires at least one scope", c.name)
|
||||
}
|
||||
// we don't resolve the tenant for managed identities because they acquire tokens only from their home tenants
|
||||
if c.name != credNameManagedIdentity {
|
||||
tenant, err := c.resolveTenant(tro.TenantID)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
tro.TenantID = tenant
|
||||
}
|
||||
client, mu, err := c.client(ctx, tro)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
var ar confidential.AuthResult
|
||||
if c.opts.Assertion != "" {
|
||||
ar, err = client.AcquireTokenOnBehalfOf(ctx, c.opts.Assertion, tro.Scopes, confidential.WithClaims(tro.Claims), confidential.WithTenantID(tro.TenantID))
|
||||
} else {
|
||||
ar, err = client.AcquireTokenSilent(ctx, tro.Scopes, confidential.WithClaims(tro.Claims), confidential.WithTenantID(tro.TenantID))
|
||||
if err != nil {
|
||||
ar, err = client.AcquireTokenByCredential(ctx, tro.Scopes, confidential.WithClaims(tro.Claims), confidential.WithTenantID(tro.TenantID))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// We could get a credentialUnavailableError from managed identity authentication because in that case the error comes from our code.
|
||||
// We return it directly because it affects the behavior of credential chains. Otherwise, we return AuthenticationFailedError.
|
||||
var unavailableErr *credentialUnavailableError
|
||||
if !errors.As(err, &unavailableErr) {
|
||||
res := getResponseFromError(err)
|
||||
err = newAuthenticationFailedError(c.name, err.Error(), res, err)
|
||||
}
|
||||
} else {
|
||||
msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", c.name, strings.Join(ar.GrantedScopes, ", "))
|
||||
log.Write(EventAuthentication, msg)
|
||||
}
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *confidentialClient) client(ctx context.Context, tro policy.TokenRequestOptions) (msalConfidentialClient, *sync.Mutex, error) {
|
||||
c.clientMu.Lock()
|
||||
defer c.clientMu.Unlock()
|
||||
if tro.EnableCAE {
|
||||
if c.cae == nil {
|
||||
client, err := c.newMSALClient(true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
c.cae = client
|
||||
}
|
||||
return c.cae, c.caeMu, nil
|
||||
}
|
||||
if c.noCAE == nil {
|
||||
client, err := c.newMSALClient(false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
c.noCAE = client
|
||||
}
|
||||
return c.noCAE, c.noCAEMu, nil
|
||||
}
|
||||
|
||||
func (c *confidentialClient) newMSALClient(enableCAE bool) (msalConfidentialClient, error) {
|
||||
authority := runtime.JoinPaths(c.host, c.tenantID)
|
||||
o := []confidential.Option{
|
||||
confidential.WithAzureRegion(c.region),
|
||||
confidential.WithHTTPClient(newPipelineAdapter(&c.opts.ClientOptions)),
|
||||
}
|
||||
if enableCAE {
|
||||
o = append(o, confidential.WithClientCapabilities(cp1))
|
||||
}
|
||||
if c.opts.SendX5C {
|
||||
o = append(o, confidential.WithX5C())
|
||||
}
|
||||
if c.opts.DisableInstanceDiscovery || strings.ToLower(c.tenantID) == "adfs" {
|
||||
o = append(o, confidential.WithInstanceDiscovery(false))
|
||||
}
|
||||
return confidential.New(authority, c.clientID, c.cred, o...)
|
||||
}
|
||||
|
||||
// resolveTenant returns the correct tenant for a token request given the client's
|
||||
// configuration, or an error when that configuration doesn't allow the specified tenant
|
||||
func (c *confidentialClient) resolveTenant(specified string) (string, error) {
|
||||
return resolveTenant(c.tenantID, specified, c.name, c.opts.AdditionallyAllowedTenants)
|
||||
}
|
29
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
сгенерированный
поставляемый
29
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
сгенерированный
поставляемый
|
@ -21,6 +21,8 @@ import (
|
|||
// DefaultAzureCredentialOptions contains optional parameters for DefaultAzureCredential.
|
||||
// These options may not apply to all credentials in the chain.
|
||||
type DefaultAzureCredentialOptions struct {
|
||||
// ClientOptions has additional options for credentials that use an Azure SDK HTTP pipeline. These options don't apply
|
||||
// to credential types that authenticate via external tools such as the Azure CLI.
|
||||
azcore.ClientOptions
|
||||
|
||||
// AdditionallyAllowedTenants specifies additional tenants for which the credential may acquire tokens. Add
|
||||
|
@ -32,8 +34,7 @@ type DefaultAzureCredentialOptions struct {
|
|||
// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
|
||||
// the application responsible for ensuring the configured authority is valid and trustworthy.
|
||||
DisableInstanceDiscovery bool
|
||||
// TenantID identifies the tenant the Azure CLI should authenticate in.
|
||||
// Defaults to the CLI's default tenant, which is typically the home tenant of the user logged in to the CLI.
|
||||
// TenantID sets the default tenant for authentication via the Azure CLI and workload identity.
|
||||
TenantID string
|
||||
}
|
||||
|
||||
|
@ -83,11 +84,11 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
|
|||
creds = append(creds, &defaultCredentialErrorReporter{credType: "EnvironmentCredential", err: err})
|
||||
}
|
||||
|
||||
// workload identity requires values for AZURE_AUTHORITY_HOST, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE, AZURE_TENANT_ID
|
||||
wic, err := NewWorkloadIdentityCredential(&WorkloadIdentityCredentialOptions{
|
||||
AdditionallyAllowedTenants: additionalTenants,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
TenantID: options.TenantID,
|
||||
})
|
||||
if err == nil {
|
||||
creds = append(creds, wic)
|
||||
|
@ -95,6 +96,7 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
|
|||
errorMessages = append(errorMessages, credNameWorkloadIdentity+": "+err.Error())
|
||||
creds = append(creds, &defaultCredentialErrorReporter{credType: credNameWorkloadIdentity, err: err})
|
||||
}
|
||||
|
||||
o := &ManagedIdentityCredentialOptions{ClientOptions: options.ClientOptions}
|
||||
if ID, ok := os.LookupEnv(azureClientID); ok {
|
||||
o.ID = ClientID(ID)
|
||||
|
@ -115,9 +117,8 @@ func NewDefaultAzureCredential(options *DefaultAzureCredentialOptions) (*Default
|
|||
creds = append(creds, &defaultCredentialErrorReporter{credType: credNameAzureCLI, err: err})
|
||||
}
|
||||
|
||||
err = defaultAzureCredentialConstructorErrorHandler(len(creds), errorMessages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(errorMessages) > 0 {
|
||||
log.Writef(EventAuthentication, "NewDefaultAzureCredential failed to initialize some credentials:\n\t%s", strings.Join(errorMessages, "\n\t"))
|
||||
}
|
||||
|
||||
chain, err := NewChainedTokenCredential(creds, nil)
|
||||
|
@ -135,20 +136,6 @@ func (c *DefaultAzureCredential) GetToken(ctx context.Context, opts policy.Token
|
|||
|
||||
var _ azcore.TokenCredential = (*DefaultAzureCredential)(nil)
|
||||
|
||||
func defaultAzureCredentialConstructorErrorHandler(numberOfSuccessfulCredentials int, errorMessages []string) (err error) {
|
||||
errorMessage := strings.Join(errorMessages, "\n\t")
|
||||
|
||||
if numberOfSuccessfulCredentials == 0 {
|
||||
return errors.New(errorMessage)
|
||||
}
|
||||
|
||||
if len(errorMessages) != 0 {
|
||||
log.Writef(EventAuthentication, "NewDefaultAzureCredential failed to initialize some credentials:\n\t%s", errorMessage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// defaultCredentialErrorReporter is a substitute for credentials that couldn't be constructed.
|
||||
// Its GetToken method always returns a credentialUnavailableError having the same message as
|
||||
// the error that prevented constructing the credential. This ensures the message is present
|
||||
|
@ -185,7 +172,7 @@ func (w *timeoutWrapper) GetToken(ctx context.Context, opts policy.TokenRequestO
|
|||
defer cancel()
|
||||
tk, err = w.mic.GetToken(c, opts)
|
||||
if isAuthFailedDueToContext(err) {
|
||||
err = newCredentialUnavailableError(credNameManagedIdentity, "managed identity timed out")
|
||||
err = newCredentialUnavailableError(credNameManagedIdentity, "managed identity timed out. See https://aka.ms/azsdk/go/identity/troubleshoot#dac for more information")
|
||||
} else {
|
||||
// some managed identity implementation is available, so don't apply the timeout to future calls
|
||||
w.timeout = 0
|
||||
|
|
52
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go
сгенерированный
поставляемый
52
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go
сгенерированный
поставляемый
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
|
||||
)
|
||||
|
||||
const credNameDeviceCode = "DeviceCodeCredential"
|
||||
|
@ -74,10 +73,7 @@ type DeviceCodeMessage struct {
|
|||
// If a web browser is available, InteractiveBrowserCredential is more convenient because it
|
||||
// automatically opens a browser to the login page.
|
||||
type DeviceCodeCredential struct {
|
||||
account public.Account
|
||||
client publicClient
|
||||
s *syncer
|
||||
prompt func(context.Context, DeviceCodeMessage) error
|
||||
client *publicClient
|
||||
}
|
||||
|
||||
// NewDeviceCodeCredential creates a DeviceCodeCredential. Pass nil to accept default options.
|
||||
|
@ -87,50 +83,24 @@ func NewDeviceCodeCredential(options *DeviceCodeCredentialOptions) (*DeviceCodeC
|
|||
cp = *options
|
||||
}
|
||||
cp.init()
|
||||
c, err := getPublicClient(
|
||||
cp.ClientID, cp.TenantID, &cp.ClientOptions, public.WithInstanceDiscovery(!cp.DisableInstanceDiscovery),
|
||||
)
|
||||
msalOpts := publicClientOptions{
|
||||
AdditionallyAllowedTenants: cp.AdditionallyAllowedTenants,
|
||||
ClientOptions: cp.ClientOptions,
|
||||
DeviceCodePrompt: cp.UserPrompt,
|
||||
DisableInstanceDiscovery: cp.DisableInstanceDiscovery,
|
||||
}
|
||||
c, err := newPublicClient(cp.TenantID, cp.ClientID, credNameDeviceCode, msalOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cred := DeviceCodeCredential{client: c, prompt: cp.UserPrompt}
|
||||
cred.s = newSyncer(credNameDeviceCode, cp.TenantID, cp.AdditionallyAllowedTenants, cred.requestToken, cred.silentAuth)
|
||||
return &cred, nil
|
||||
c.name = credNameDeviceCode
|
||||
return &DeviceCodeCredential{client: c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. It will begin the device code flow and poll until the user completes authentication.
|
||||
// This method is called automatically by Azure SDK clients.
|
||||
func (c *DeviceCodeCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *DeviceCodeCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
dc, err := c.client.AcquireTokenByDeviceCode(ctx, opts.Scopes, public.WithTenantID(opts.TenantID))
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
err = c.prompt(ctx, DeviceCodeMessage{
|
||||
Message: dc.Result.Message,
|
||||
UserCode: dc.Result.UserCode,
|
||||
VerificationURL: dc.Result.VerificationURL,
|
||||
})
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
ar, err := dc.AuthenticationResult(ctx)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
c.account = ar.Account
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *DeviceCodeCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes,
|
||||
public.WithSilentAccount(c.account),
|
||||
public.WithTenantID(opts.TenantID),
|
||||
)
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*DeviceCodeCredential)(nil)
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo"
|
||||
msal "github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
|
||||
)
|
||||
|
@ -57,17 +57,16 @@ func (e *AuthenticationFailedError) Error() string {
|
|||
fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
|
||||
fmt.Fprintf(msg, "RESPONSE %s\n", e.RawResponse.Status)
|
||||
fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
|
||||
body, err := io.ReadAll(e.RawResponse.Body)
|
||||
e.RawResponse.Body.Close()
|
||||
if err != nil {
|
||||
body, err := runtime.Payload(e.RawResponse)
|
||||
switch {
|
||||
case err != nil:
|
||||
fmt.Fprintf(msg, "Error reading response body: %v", err)
|
||||
} else if len(body) > 0 {
|
||||
e.RawResponse.Body = io.NopCloser(bytes.NewReader(body))
|
||||
case len(body) > 0:
|
||||
if err := json.Indent(msg, body, "", " "); err != nil {
|
||||
// failed to pretty-print so just dump it verbatim
|
||||
fmt.Fprint(msg, string(body))
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
fmt.Fprint(msg, "Response contained no body")
|
||||
}
|
||||
fmt.Fprintln(msg, "\n--------------------------------------------------------------------------------")
|
||||
|
|
40
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go
сгенерированный
поставляемый
40
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go
сгенерированный
поставляемый
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
|
||||
)
|
||||
|
||||
const credNameBrowser = "InteractiveBrowserCredential"
|
||||
|
@ -56,10 +55,7 @@ func (o *InteractiveBrowserCredentialOptions) init() {
|
|||
|
||||
// InteractiveBrowserCredential opens a browser to interactively authenticate a user.
|
||||
type InteractiveBrowserCredential struct {
|
||||
account public.Account
|
||||
client publicClient
|
||||
options InteractiveBrowserCredentialOptions
|
||||
s *syncer
|
||||
client *publicClient
|
||||
}
|
||||
|
||||
// NewInteractiveBrowserCredential constructs a new InteractiveBrowserCredential. Pass nil to accept default options.
|
||||
|
@ -69,38 +65,22 @@ func NewInteractiveBrowserCredential(options *InteractiveBrowserCredentialOption
|
|||
cp = *options
|
||||
}
|
||||
cp.init()
|
||||
c, err := getPublicClient(cp.ClientID, cp.TenantID, &cp.ClientOptions, public.WithInstanceDiscovery(!cp.DisableInstanceDiscovery))
|
||||
msalOpts := publicClientOptions{
|
||||
ClientOptions: cp.ClientOptions,
|
||||
DisableInstanceDiscovery: cp.DisableInstanceDiscovery,
|
||||
LoginHint: cp.LoginHint,
|
||||
RedirectURL: cp.RedirectURL,
|
||||
}
|
||||
c, err := newPublicClient(cp.TenantID, cp.ClientID, credNameBrowser, msalOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ibc := InteractiveBrowserCredential{client: c, options: cp}
|
||||
ibc.s = newSyncer(credNameBrowser, cp.TenantID, cp.AdditionallyAllowedTenants, ibc.requestToken, ibc.silentAuth)
|
||||
return &ibc, nil
|
||||
return &InteractiveBrowserCredential{client: c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (c *InteractiveBrowserCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *InteractiveBrowserCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenInteractive(ctx, opts.Scopes,
|
||||
public.WithLoginHint(c.options.LoginHint),
|
||||
public.WithRedirectURI(c.options.RedirectURL),
|
||||
public.WithTenantID(opts.TenantID),
|
||||
)
|
||||
if err == nil {
|
||||
c.account = ar.Account
|
||||
}
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *InteractiveBrowserCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes,
|
||||
public.WithSilentAccount(c.account),
|
||||
public.WithTenantID(opts.TenantID),
|
||||
)
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*InteractiveBrowserCredential)(nil)
|
||||
|
|
28
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go
сгенерированный
поставляемый
28
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go
сгенерированный
поставляемый
|
@ -84,13 +84,15 @@ func setIMDSRetryOptionDefaults(o *policy.RetryOptions) {
|
|||
}
|
||||
if o.StatusCodes == nil {
|
||||
o.StatusCodes = []int{
|
||||
// IMDS docs recommend retrying 404, 429 and all 5xx
|
||||
// https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#error-handling
|
||||
// IMDS docs recommend retrying 404, 410, 429 and 5xx
|
||||
// https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#error-handling
|
||||
http.StatusNotFound, // 404
|
||||
http.StatusGone, // 410
|
||||
http.StatusTooManyRequests, // 429
|
||||
http.StatusInternalServerError, // 500
|
||||
http.StatusNotImplemented, // 501
|
||||
http.StatusBadGateway, // 502
|
||||
http.StatusServiceUnavailable, // 503
|
||||
http.StatusGatewayTimeout, // 504
|
||||
http.StatusHTTPVersionNotSupported, // 505
|
||||
http.StatusVariantAlsoNegotiates, // 506
|
||||
|
@ -175,11 +177,25 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
|
|||
return c.createAccessToken(resp)
|
||||
}
|
||||
|
||||
if c.msiType == msiTypeIMDS && resp.StatusCode == 400 {
|
||||
if id != nil {
|
||||
return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "the requested identity isn't assigned to this resource", resp, nil)
|
||||
if c.msiType == msiTypeIMDS {
|
||||
switch resp.StatusCode {
|
||||
case http.StatusBadRequest:
|
||||
if id != nil {
|
||||
return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "the requested identity isn't assigned to this resource", resp, nil)
|
||||
}
|
||||
msg := "failed to authenticate a system assigned identity"
|
||||
if body, err := runtime.Payload(resp); err == nil && len(body) > 0 {
|
||||
msg += fmt.Sprintf(". The endpoint responded with %s", body)
|
||||
}
|
||||
return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, msg)
|
||||
case http.StatusForbidden:
|
||||
// Docker Desktop runs a proxy that responds 403 to IMDS token requests. If we get that response,
|
||||
// we return credentialUnavailableError so credential chains continue to their next credential
|
||||
body, err := runtime.Payload(resp)
|
||||
if err == nil && strings.Contains(string(body), "A socket operation was attempted to an unreachable network") {
|
||||
return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, fmt.Sprintf("unexpected response %q", string(body)))
|
||||
}
|
||||
}
|
||||
return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, "no default identity is assigned to this resource")
|
||||
}
|
||||
|
||||
return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "authentication failed", resp, nil)
|
||||
|
|
26
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go
сгенерированный
поставляемый
26
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go
сгенерированный
поставляемый
|
@ -8,7 +8,6 @@ package azidentity
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
|
@ -71,9 +70,8 @@ type ManagedIdentityCredentialOptions struct {
|
|||
// user-assigned identity. See Azure Active Directory documentation for more information about managed identities:
|
||||
// https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview
|
||||
type ManagedIdentityCredential struct {
|
||||
client confidentialClient
|
||||
client *confidentialClient
|
||||
mic *managedIdentityClient
|
||||
s *syncer
|
||||
}
|
||||
|
||||
// NewManagedIdentityCredential creates a ManagedIdentityCredential. Pass nil to accept default options.
|
||||
|
@ -93,35 +91,23 @@ func NewManagedIdentityCredential(options *ManagedIdentityCredentialOptions) (*M
|
|||
if options.ID != nil {
|
||||
clientID = options.ID.String()
|
||||
}
|
||||
// similarly, it's okay to give MSAL an incorrect authority URL because that URL won't be used
|
||||
c, err := confidential.New("https://login.microsoftonline.com/common", clientID, cred)
|
||||
// similarly, it's okay to give MSAL an incorrect tenant because MSAL won't use the value
|
||||
c, err := newConfidentialClient("common", clientID, credNameManagedIdentity, cred, confidentialClientOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := ManagedIdentityCredential{client: c, mic: mic}
|
||||
m.s = newSyncer(credNameManagedIdentity, "", nil, m.requestToken, m.silentAuth)
|
||||
return &m, nil
|
||||
return &ManagedIdentityCredential{client: c, mic: mic}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from the hosting environment. This method is called automatically by Azure SDK clients.
|
||||
func (c *ManagedIdentityCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
if len(opts.Scopes) != 1 {
|
||||
err := errors.New(credNameManagedIdentity + ": GetToken() requires exactly one scope")
|
||||
err := fmt.Errorf("%s.GetToken() requires exactly one scope", credNameManagedIdentity)
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
// managed identity endpoints require an AADv1 resource (i.e. token audience), not a v2 scope, so we remove "/.default" here
|
||||
opts.Scopes = []string{strings.TrimSuffix(opts.Scopes[0], defaultSuffix)}
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *ManagedIdentityCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenByCredential(ctx, opts.Scopes)
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *ManagedIdentityCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes)
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*ManagedIdentityCredential)(nil)
|
||||
|
|
27
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/on_behalf_of_credential.go
сгенерированный
поставляемый
27
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/on_behalf_of_credential.go
сгенерированный
поставляемый
|
@ -25,9 +25,7 @@ const credNameOBO = "OnBehalfOfCredential"
|
|||
//
|
||||
// [Azure Active Directory documentation]: https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
|
||||
type OnBehalfOfCredential struct {
|
||||
assertion string
|
||||
client confidentialClient
|
||||
s *syncer
|
||||
client *confidentialClient
|
||||
}
|
||||
|
||||
// OnBehalfOfCredentialOptions contains optional parameters for OnBehalfOfCredential
|
||||
|
@ -72,28 +70,23 @@ func newOnBehalfOfCredential(tenantID, clientID, userAssertion string, cred conf
|
|||
if options == nil {
|
||||
options = &OnBehalfOfCredentialOptions{}
|
||||
}
|
||||
opts := []confidential.Option{}
|
||||
if options.SendCertificateChain {
|
||||
opts = append(opts, confidential.WithX5C())
|
||||
opts := confidentialClientOptions{
|
||||
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
|
||||
Assertion: userAssertion,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
SendX5C: options.SendCertificateChain,
|
||||
}
|
||||
opts = append(opts, confidential.WithInstanceDiscovery(!options.DisableInstanceDiscovery))
|
||||
c, err := getConfidentialClient(clientID, tenantID, cred, &options.ClientOptions, opts...)
|
||||
c, err := newConfidentialClient(tenantID, clientID, credNameOBO, cred, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obo := OnBehalfOfCredential{assertion: userAssertion, client: c}
|
||||
obo.s = newSyncer(credNameOBO, tenantID, options.AdditionallyAllowedTenants, obo.requestToken, obo.requestToken)
|
||||
return &obo, nil
|
||||
return &OnBehalfOfCredential{c}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (o *OnBehalfOfCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return o.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (o *OnBehalfOfCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := o.client.AcquireTokenOnBehalfOf(ctx, o.assertion, opts.Scopes, confidential.WithTenantID(opts.TenantID))
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return o.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*OnBehalfOfCredential)(nil)
|
||||
|
|
178
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go
сгенерированный
поставляемый
Normal file
178
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,178 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azidentity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
|
||||
)
|
||||
|
||||
type publicClientOptions struct {
|
||||
azcore.ClientOptions
|
||||
|
||||
AdditionallyAllowedTenants []string
|
||||
DeviceCodePrompt func(context.Context, DeviceCodeMessage) error
|
||||
DisableInstanceDiscovery bool
|
||||
LoginHint, RedirectURL string
|
||||
Username, Password string
|
||||
}
|
||||
|
||||
// publicClient wraps the MSAL public client
|
||||
type publicClient struct {
|
||||
account public.Account
|
||||
cae, noCAE msalPublicClient
|
||||
caeMu, noCAEMu, clientMu *sync.Mutex
|
||||
clientID, tenantID string
|
||||
host string
|
||||
name string
|
||||
opts publicClientOptions
|
||||
}
|
||||
|
||||
func newPublicClient(tenantID, clientID, name string, o publicClientOptions) (*publicClient, error) {
|
||||
if !validTenantID(tenantID) {
|
||||
return nil, errInvalidTenantID
|
||||
}
|
||||
host, err := setAuthorityHost(o.Cloud)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o.AdditionallyAllowedTenants = resolveAdditionalTenants(o.AdditionallyAllowedTenants)
|
||||
return &publicClient{
|
||||
caeMu: &sync.Mutex{},
|
||||
clientID: clientID,
|
||||
clientMu: &sync.Mutex{},
|
||||
host: host,
|
||||
name: name,
|
||||
noCAEMu: &sync.Mutex{},
|
||||
opts: o,
|
||||
tenantID: tenantID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetToken requests an access token from MSAL, checking the cache first.
|
||||
func (p *publicClient) GetToken(ctx context.Context, tro policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
if len(tro.Scopes) < 1 {
|
||||
return azcore.AccessToken{}, fmt.Errorf("%s.GetToken() requires at least one scope", p.name)
|
||||
}
|
||||
tenant, err := p.resolveTenant(tro.TenantID)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
client, mu, err := p.client(tro)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
ar, err := client.AcquireTokenSilent(ctx, tro.Scopes, public.WithSilentAccount(p.account), public.WithClaims(tro.Claims), public.WithTenantID(tenant))
|
||||
if err == nil {
|
||||
return p.token(ar, err)
|
||||
}
|
||||
at, err := p.reqToken(ctx, client, tro)
|
||||
if err == nil {
|
||||
msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", p.name, strings.Join(ar.GrantedScopes, ", "))
|
||||
log.Write(EventAuthentication, msg)
|
||||
}
|
||||
return at, err
|
||||
}
|
||||
|
||||
// reqToken requests a token from the MSAL public client. It's separate from GetToken() to enable Authenticate() to bypass the cache.
|
||||
func (p *publicClient) reqToken(ctx context.Context, c msalPublicClient, tro policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
tenant, err := p.resolveTenant(tro.TenantID)
|
||||
if err != nil {
|
||||
return azcore.AccessToken{}, err
|
||||
}
|
||||
var ar public.AuthResult
|
||||
switch p.name {
|
||||
case credNameBrowser:
|
||||
ar, err = c.AcquireTokenInteractive(ctx, tro.Scopes,
|
||||
public.WithClaims(tro.Claims),
|
||||
public.WithLoginHint(p.opts.LoginHint),
|
||||
public.WithRedirectURI(p.opts.RedirectURL),
|
||||
public.WithTenantID(tenant),
|
||||
)
|
||||
case credNameDeviceCode:
|
||||
dc, e := c.AcquireTokenByDeviceCode(ctx, tro.Scopes, public.WithClaims(tro.Claims), public.WithTenantID(tenant))
|
||||
if e != nil {
|
||||
return azcore.AccessToken{}, e
|
||||
}
|
||||
err = p.opts.DeviceCodePrompt(ctx, DeviceCodeMessage{
|
||||
Message: dc.Result.Message,
|
||||
UserCode: dc.Result.UserCode,
|
||||
VerificationURL: dc.Result.VerificationURL,
|
||||
})
|
||||
if err == nil {
|
||||
ar, err = dc.AuthenticationResult(ctx)
|
||||
}
|
||||
case credNameUserPassword:
|
||||
ar, err = c.AcquireTokenByUsernamePassword(ctx, tro.Scopes, p.opts.Username, p.opts.Password, public.WithClaims(tro.Claims), public.WithTenantID(tenant))
|
||||
default:
|
||||
return azcore.AccessToken{}, fmt.Errorf("unknown credential %q", p.name)
|
||||
}
|
||||
return p.token(ar, err)
|
||||
}
|
||||
|
||||
func (p *publicClient) client(tro policy.TokenRequestOptions) (msalPublicClient, *sync.Mutex, error) {
|
||||
p.clientMu.Lock()
|
||||
defer p.clientMu.Unlock()
|
||||
if tro.EnableCAE {
|
||||
if p.cae == nil {
|
||||
client, err := p.newMSALClient(true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p.cae = client
|
||||
}
|
||||
return p.cae, p.caeMu, nil
|
||||
}
|
||||
if p.noCAE == nil {
|
||||
client, err := p.newMSALClient(false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p.noCAE = client
|
||||
}
|
||||
return p.noCAE, p.noCAEMu, nil
|
||||
}
|
||||
|
||||
func (p *publicClient) newMSALClient(enableCAE bool) (msalPublicClient, error) {
|
||||
o := []public.Option{
|
||||
public.WithAuthority(runtime.JoinPaths(p.host, p.tenantID)),
|
||||
public.WithHTTPClient(newPipelineAdapter(&p.opts.ClientOptions)),
|
||||
}
|
||||
if enableCAE {
|
||||
o = append(o, public.WithClientCapabilities(cp1))
|
||||
}
|
||||
if p.opts.DisableInstanceDiscovery || strings.ToLower(p.tenantID) == "adfs" {
|
||||
o = append(o, public.WithInstanceDiscovery(false))
|
||||
}
|
||||
return public.New(p.clientID, o...)
|
||||
}
|
||||
|
||||
func (p *publicClient) token(ar public.AuthResult, err error) (azcore.AccessToken, error) {
|
||||
if err == nil {
|
||||
p.account = ar.Account
|
||||
} else {
|
||||
res := getResponseFromError(err)
|
||||
err = newAuthenticationFailedError(p.name, err.Error(), res, err)
|
||||
}
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
// resolveTenant returns the correct tenant for a token request given the client's
|
||||
// configuration, or an error when that configuration doesn't allow the specified tenant
|
||||
func (p *publicClient) resolveTenant(specified string) (string, error) {
|
||||
return resolveTenant(p.tenantID, specified, p.name, p.opts.AdditionallyAllowedTenants)
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package azidentity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/internal/log"
|
||||
)
|
||||
|
||||
type authFn func(context.Context, policy.TokenRequestOptions) (azcore.AccessToken, error)
|
||||
|
||||
// syncer synchronizes authentication calls so that goroutines can share a credential instance
|
||||
type syncer struct {
|
||||
addlTenants []string
|
||||
authing bool
|
||||
cond *sync.Cond
|
||||
reqToken, silent authFn
|
||||
name, tenant string
|
||||
}
|
||||
|
||||
func newSyncer(name, tenant string, additionalTenants []string, reqToken, silentAuth authFn) *syncer {
|
||||
return &syncer{
|
||||
addlTenants: resolveAdditionalTenants(additionalTenants),
|
||||
cond: &sync.Cond{L: &sync.Mutex{}},
|
||||
name: name,
|
||||
reqToken: reqToken,
|
||||
silent: silentAuth,
|
||||
tenant: tenant,
|
||||
}
|
||||
}
|
||||
|
||||
// GetToken ensures that only one goroutine authenticates at a time
|
||||
func (s *syncer) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
var at azcore.AccessToken
|
||||
var err error
|
||||
if len(opts.Scopes) == 0 {
|
||||
return at, errors.New(s.name + ".GetToken() requires at least one scope")
|
||||
}
|
||||
// we don't resolve the tenant for managed identities because they can acquire tokens only from their home tenants
|
||||
if s.name != credNameManagedIdentity {
|
||||
tenant, err := s.resolveTenant(opts.TenantID)
|
||||
if err != nil {
|
||||
return at, err
|
||||
}
|
||||
opts.TenantID = tenant
|
||||
}
|
||||
auth := false
|
||||
s.cond.L.Lock()
|
||||
defer s.cond.L.Unlock()
|
||||
for {
|
||||
at, err = s.silent(ctx, opts)
|
||||
if err == nil {
|
||||
// got a token
|
||||
break
|
||||
}
|
||||
if !s.authing {
|
||||
// this goroutine will request a token
|
||||
s.authing, auth = true, true
|
||||
break
|
||||
}
|
||||
// another goroutine is acquiring a token; wait for it to finish, then try silent auth again
|
||||
s.cond.Wait()
|
||||
}
|
||||
if auth {
|
||||
s.authing = false
|
||||
at, err = s.reqToken(ctx, opts)
|
||||
s.cond.Broadcast()
|
||||
}
|
||||
if err != nil {
|
||||
// Return credentialUnavailableError directly because that type affects the behavior of credential chains.
|
||||
// Otherwise, return AuthenticationFailedError.
|
||||
var unavailableErr *credentialUnavailableError
|
||||
if !errors.As(err, &unavailableErr) {
|
||||
res := getResponseFromError(err)
|
||||
err = newAuthenticationFailedError(s.name, err.Error(), res, err)
|
||||
}
|
||||
} else if log.Should(EventAuthentication) {
|
||||
scope := strings.Join(opts.Scopes, ", ")
|
||||
msg := fmt.Sprintf(`%s.GetToken() acquired a token for scope "%s"\n`, s.name, scope)
|
||||
log.Write(EventAuthentication, msg)
|
||||
}
|
||||
return at, err
|
||||
}
|
||||
|
||||
// resolveTenant returns the correct tenant for a token request given the credential's
|
||||
// configuration, or an error when the specified tenant isn't allowed by that configuration
|
||||
func (s *syncer) resolveTenant(requested string) (string, error) {
|
||||
if requested == "" || requested == s.tenant {
|
||||
return s.tenant, nil
|
||||
}
|
||||
if s.tenant == "adfs" {
|
||||
return "", errors.New("ADFS doesn't support tenants")
|
||||
}
|
||||
if !validTenantID(requested) {
|
||||
return "", errors.New(tenantIDValidationErr)
|
||||
}
|
||||
for _, t := range s.addlTenants {
|
||||
if t == "*" || t == requested {
|
||||
return requested, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf(`%s isn't configured to acquire tokens for tenant %q. To enable acquiring tokens for this tenant add it to the AdditionallyAllowedTenants on the credential options, or add "*" to allow acquiring tokens for any tenant`, s.name, requested)
|
||||
}
|
||||
|
||||
// resolveAdditionalTenants returns a copy of tenants, simplified when tenants contains a wildcard
|
||||
func resolveAdditionalTenants(tenants []string) []string {
|
||||
if len(tenants) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, t := range tenants {
|
||||
// a wildcard makes all other values redundant
|
||||
if t == "*" {
|
||||
return []string{"*"}
|
||||
}
|
||||
}
|
||||
cp := make([]string, len(tenants))
|
||||
copy(cp, tenants)
|
||||
return cp
|
||||
}
|
36
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-pre.ps1
сгенерированный
поставляемый
Normal file
36
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-pre.ps1
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,36 @@
|
|||
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
|
||||
param (
|
||||
# Captures any arguments from eng/New-TestResources.ps1 not declared here (no parameter errors).
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
$RemainingArguments
|
||||
)
|
||||
|
||||
if (!$CI) {
|
||||
# TODO: Remove this once auto-cloud config downloads are supported locally
|
||||
Write-Host "Skipping cert setup in local testing mode"
|
||||
return
|
||||
}
|
||||
|
||||
if ($EnvironmentVariables -eq $null -or $EnvironmentVariables.Count -eq 0) {
|
||||
throw "EnvironmentVariables must be set in the calling script New-TestResources.ps1"
|
||||
}
|
||||
|
||||
$tmp = $env:TEMP ? $env:TEMP : [System.IO.Path]::GetTempPath()
|
||||
$pfxPath = Join-Path $tmp "test.pfx"
|
||||
$pemPath = Join-Path $tmp "test.pem"
|
||||
$sniPath = Join-Path $tmp "testsni.pfx"
|
||||
|
||||
Write-Host "Creating identity test files: $pfxPath $pemPath $sniPath"
|
||||
|
||||
[System.Convert]::FromBase64String($EnvironmentVariables['PFX_CONTENTS']) | Set-Content -Path $pfxPath -AsByteStream
|
||||
Set-Content -Path $pemPath -Value $EnvironmentVariables['PEM_CONTENTS']
|
||||
[System.Convert]::FromBase64String($EnvironmentVariables['SNI_CONTENTS']) | Set-Content -Path $sniPath -AsByteStream
|
||||
|
||||
# Set for pipeline
|
||||
Write-Host "##vso[task.setvariable variable=IDENTITY_SP_CERT_PFX;]$pfxPath"
|
||||
Write-Host "##vso[task.setvariable variable=IDENTITY_SP_CERT_PEM;]$pemPath"
|
||||
Write-Host "##vso[task.setvariable variable=IDENTITY_SP_CERT_SNI;]$sniPath"
|
||||
# Set for local
|
||||
$env:IDENTITY_SP_CERT_PFX = $pfxPath
|
||||
$env:IDENTITY_SP_CERT_PEM = $pemPath
|
||||
$env:IDENTITY_SP_CERT_SNI = $sniPath
|
1
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep
сгенерированный
поставляемый
Normal file
1
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1 @@
|
|||
param baseName string
|
37
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go
сгенерированный
поставляемый
37
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go
сгенерированный
поставляемый
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
|
||||
)
|
||||
|
||||
const credNameUserPassword = "UsernamePasswordCredential"
|
||||
|
@ -36,10 +35,7 @@ type UsernamePasswordCredentialOptions struct {
|
|||
// with any form of multi-factor authentication, and the application must already have user or admin consent.
|
||||
// This credential can only authenticate work and school accounts; it can't authenticate Microsoft accounts.
|
||||
type UsernamePasswordCredential struct {
|
||||
account public.Account
|
||||
client publicClient
|
||||
password, username string
|
||||
s *syncer
|
||||
client *publicClient
|
||||
}
|
||||
|
||||
// NewUsernamePasswordCredential creates a UsernamePasswordCredential. clientID is the ID of the application the user
|
||||
|
@ -48,34 +44,23 @@ func NewUsernamePasswordCredential(tenantID string, clientID string, username st
|
|||
if options == nil {
|
||||
options = &UsernamePasswordCredentialOptions{}
|
||||
}
|
||||
c, err := getPublicClient(clientID, tenantID, &options.ClientOptions, public.WithInstanceDiscovery(!options.DisableInstanceDiscovery))
|
||||
opts := publicClientOptions{
|
||||
AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
|
||||
ClientOptions: options.ClientOptions,
|
||||
DisableInstanceDiscovery: options.DisableInstanceDiscovery,
|
||||
Password: password,
|
||||
Username: username,
|
||||
}
|
||||
c, err := newPublicClient(tenantID, clientID, credNameUserPassword, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
upc := UsernamePasswordCredential{client: c, password: password, username: username}
|
||||
upc.s = newSyncer(credNameUserPassword, tenantID, options.AdditionallyAllowedTenants, upc.requestToken, upc.silentAuth)
|
||||
return &upc, nil
|
||||
return &UsernamePasswordCredential{client: c}, err
|
||||
}
|
||||
|
||||
// GetToken requests an access token from Azure Active Directory. This method is called automatically by Azure SDK clients.
|
||||
func (c *UsernamePasswordCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
return c.s.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
func (c *UsernamePasswordCredential) requestToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenByUsernamePassword(ctx, opts.Scopes, c.username, c.password, public.WithTenantID(opts.TenantID))
|
||||
if err == nil {
|
||||
c.account = ar.Account
|
||||
}
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
}
|
||||
|
||||
func (c *UsernamePasswordCredential) silentAuth(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
|
||||
ar, err := c.client.AcquireTokenSilent(ctx, opts.Scopes,
|
||||
public.WithSilentAccount(c.account),
|
||||
public.WithTenantID(opts.TenantID),
|
||||
)
|
||||
return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
|
||||
return c.client.GetToken(ctx, opts)
|
||||
}
|
||||
|
||||
var _ azcore.TokenCredential = (*UsernamePasswordCredential)(nil)
|
||||
|
|
|
@ -11,5 +11,5 @@ const (
|
|||
component = "azidentity"
|
||||
|
||||
// Version is the semantic version (see http://semver.org) of this module.
|
||||
version = "v1.3.1"
|
||||
version = "v1.4.0"
|
||||
)
|
||||
|
|
4
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go
сгенерированный
поставляемый
4
vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go
сгенерированный
поставляемый
|
@ -47,7 +47,7 @@ type WorkloadIdentityCredentialOptions struct {
|
|||
DisableInstanceDiscovery bool
|
||||
// TenantID of the service principal. Defaults to the value of the environment variable AZURE_TENANT_ID.
|
||||
TenantID string
|
||||
// TokenFilePath is the path a file containing the workload identity token. Defaults to the value of the
|
||||
// TokenFilePath is the path of a file containing a Kubernetes service account token. Defaults to the value of the
|
||||
// environment variable AZURE_FEDERATED_TOKEN_FILE.
|
||||
TokenFilePath string
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ func NewWorkloadIdentityCredential(options *WorkloadIdentityCredentialOptions) (
|
|||
return nil, err
|
||||
}
|
||||
// we want "WorkloadIdentityCredential" in log messages, not "ClientAssertionCredential"
|
||||
cred.s.name = credNameWorkloadIdentity
|
||||
cred.client.name = credNameWorkloadIdentity
|
||||
w.cred = cred
|
||||
return &w, nil
|
||||
}
|
||||
|
|
83
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/CHANGELOG.md
сгенерированный
поставляемый
Normal file
83
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/CHANGELOG.md
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,83 @@
|
|||
# Release History
|
||||
|
||||
## 1.4.0 (2023-11-24)
|
||||
### Features Added
|
||||
|
||||
- Support for test fakes and OpenTelemetry trace spans.
|
||||
|
||||
|
||||
## 1.3.0 (2023-10-27)
|
||||
### Features Added
|
||||
|
||||
- New value `ManagedHsmSKUNameCustomB6` added to enum type `ManagedHsmSKUName`
|
||||
- New enum type `ManagedServiceIdentityType` with values `ManagedServiceIdentityTypeNone`, `ManagedServiceIdentityTypeSystemAssigned`, `ManagedServiceIdentityTypeSystemAssignedUserAssigned`, `ManagedServiceIdentityTypeUserAssigned`
|
||||
- New struct `ManagedServiceIdentity`
|
||||
- New struct `UserAssignedIdentity`
|
||||
- New field `Identity` in struct `MHSMPrivateEndpointConnection`
|
||||
- New field `Identity` in struct `MHSMPrivateLinkResource`
|
||||
- New field `Identity` in struct `ManagedHsm`
|
||||
|
||||
|
||||
## 1.2.0 (2023-04-28)
|
||||
### Features Added
|
||||
|
||||
- New value `JSONWebKeyOperationRelease` added to enum type `JSONWebKeyOperation`
|
||||
- New value `KeyPermissionsGetrotationpolicy`, `KeyPermissionsRelease`, `KeyPermissionsRotate`, `KeyPermissionsSetrotationpolicy` added to enum type `KeyPermissions`
|
||||
- New enum type `ActivationStatus` with values `ActivationStatusActive`, `ActivationStatusFailed`, `ActivationStatusNotActivated`, `ActivationStatusUnknown`
|
||||
- New enum type `GeoReplicationRegionProvisioningState` with values `GeoReplicationRegionProvisioningStateCleanup`, `GeoReplicationRegionProvisioningStateDeleting`, `GeoReplicationRegionProvisioningStateFailed`, `GeoReplicationRegionProvisioningStatePreprovisioning`, `GeoReplicationRegionProvisioningStateProvisioning`, `GeoReplicationRegionProvisioningStateSucceeded`
|
||||
- New enum type `KeyRotationPolicyActionType` with values `KeyRotationPolicyActionTypeNotify`, `KeyRotationPolicyActionTypeRotate`
|
||||
- New function `*ClientFactory.NewMHSMRegionsClient() *MHSMRegionsClient`
|
||||
- New function `*ClientFactory.NewManagedHsmKeysClient() *ManagedHsmKeysClient`
|
||||
- New function `NewMHSMRegionsClient(string, azcore.TokenCredential, *arm.ClientOptions) (*MHSMRegionsClient, error)`
|
||||
- New function `*MHSMRegionsClient.NewListByResourcePager(string, string, *MHSMRegionsClientListByResourceOptions) *runtime.Pager[MHSMRegionsClientListByResourceResponse]`
|
||||
- New function `NewManagedHsmKeysClient(string, azcore.TokenCredential, *arm.ClientOptions) (*ManagedHsmKeysClient, error)`
|
||||
- New function `*ManagedHsmKeysClient.CreateIfNotExist(context.Context, string, string, string, ManagedHsmKeyCreateParameters, *ManagedHsmKeysClientCreateIfNotExistOptions) (ManagedHsmKeysClientCreateIfNotExistResponse, error)`
|
||||
- New function `*ManagedHsmKeysClient.Get(context.Context, string, string, string, *ManagedHsmKeysClientGetOptions) (ManagedHsmKeysClientGetResponse, error)`
|
||||
- New function `*ManagedHsmKeysClient.GetVersion(context.Context, string, string, string, string, *ManagedHsmKeysClientGetVersionOptions) (ManagedHsmKeysClientGetVersionResponse, error)`
|
||||
- New function `*ManagedHsmKeysClient.NewListPager(string, string, *ManagedHsmKeysClientListOptions) *runtime.Pager[ManagedHsmKeysClientListResponse]`
|
||||
- New function `*ManagedHsmKeysClient.NewListVersionsPager(string, string, string, *ManagedHsmKeysClientListVersionsOptions) *runtime.Pager[ManagedHsmKeysClientListVersionsResponse]`
|
||||
- New function `*ManagedHsmsClient.CheckMhsmNameAvailability(context.Context, CheckMhsmNameAvailabilityParameters, *ManagedHsmsClientCheckMhsmNameAvailabilityOptions) (ManagedHsmsClientCheckMhsmNameAvailabilityResponse, error)`
|
||||
- New struct `Action`
|
||||
- New struct `CheckMhsmNameAvailabilityParameters`
|
||||
- New struct `CheckMhsmNameAvailabilityResult`
|
||||
- New struct `KeyReleasePolicy`
|
||||
- New struct `KeyRotationPolicyAttributes`
|
||||
- New struct `LifetimeAction`
|
||||
- New struct `MHSMGeoReplicatedRegion`
|
||||
- New struct `MHSMRegionsListResult`
|
||||
- New struct `ManagedHSMSecurityDomainProperties`
|
||||
- New struct `ManagedHsmAction`
|
||||
- New struct `ManagedHsmKey`
|
||||
- New struct `ManagedHsmKeyAttributes`
|
||||
- New struct `ManagedHsmKeyCreateParameters`
|
||||
- New struct `ManagedHsmKeyListResult`
|
||||
- New struct `ManagedHsmKeyProperties`
|
||||
- New struct `ManagedHsmKeyReleasePolicy`
|
||||
- New struct `ManagedHsmKeyRotationPolicyAttributes`
|
||||
- New struct `ManagedHsmLifetimeAction`
|
||||
- New struct `ManagedHsmRotationPolicy`
|
||||
- New struct `ManagedHsmTrigger`
|
||||
- New struct `ProxyResourceWithoutSystemData`
|
||||
- New struct `RotationPolicy`
|
||||
- New struct `Trigger`
|
||||
- New field `ReleasePolicy` in struct `KeyProperties`
|
||||
- New field `RotationPolicy` in struct `KeyProperties`
|
||||
- New field `Etag` in struct `MHSMPrivateEndpointConnectionItem`
|
||||
- New field `ID` in struct `MHSMPrivateEndpointConnectionItem`
|
||||
- New field `Regions` in struct `ManagedHsmProperties`
|
||||
- New field `SecurityDomainProperties` in struct `ManagedHsmProperties`
|
||||
|
||||
|
||||
## 1.1.0 (2023-04-06)
|
||||
### Features Added
|
||||
|
||||
- New struct `ClientFactory` which is a client factory used to create any client in this module
|
||||
|
||||
|
||||
## 1.0.0 (2022-05-16)
|
||||
|
||||
The package of `github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault` is using our [next generation design principles](https://azure.github.io/azure-sdk/general_introduction.html) since version 1.0.0, which contains breaking changes.
|
||||
|
||||
To migrate the existing applications to the latest version, please refer to [Migration Guide](https://aka.ms/azsdk/go/mgmt/migration).
|
||||
|
||||
To learn more, please refer to our documentation [Quick Start](https://aka.ms/azsdk/go/mgmt).
|
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/LICENSE.txt
сгенерированный
поставляемый
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/LICENSE.txt
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
98
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/README.md
сгенерированный
поставляемый
Normal file
98
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/README.md
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,98 @@
|
|||
# Azure Key Vault Module for Go
|
||||
|
||||
[![PkgGoDev](https://pkg.go.dev/badge/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault)](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault)
|
||||
|
||||
The `armkeyvault` module provides operations for working with Azure Key Vault.
|
||||
|
||||
[Source code](https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/resourcemanager/keyvault/armkeyvault)
|
||||
|
||||
# Getting started
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- an [Azure subscription](https://azure.microsoft.com/free/)
|
||||
- Go 1.18 or above (You could download and install the latest version of Go from [here](https://go.dev/doc/install). It will replace the existing Go on your machine. If you want to install multiple Go versions on the same machine, you could refer this [doc](https://go.dev/doc/manage-install).)
|
||||
|
||||
## Install the package
|
||||
|
||||
This project uses [Go modules](https://github.com/golang/go/wiki/Modules) for versioning and dependency management.
|
||||
|
||||
Install the Azure Key Vault module:
|
||||
|
||||
```sh
|
||||
go get github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault
|
||||
```
|
||||
|
||||
## Authorization
|
||||
|
||||
When creating a client, you will need to provide a credential for authenticating with Azure Key Vault. The `azidentity` module provides facilities for various ways of authenticating with Azure including client/secret, certificate, managed identity, and more.
|
||||
|
||||
```go
|
||||
cred, err := azidentity.NewDefaultAzureCredential(nil)
|
||||
```
|
||||
|
||||
For more information on authentication, please see the documentation for `azidentity` at [pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity).
|
||||
|
||||
## Client Factory
|
||||
|
||||
Azure Key Vault module consists of one or more clients. We provide a client factory which could be used to create any client in this module.
|
||||
|
||||
```go
|
||||
clientFactory, err := armkeyvault.NewClientFactory(<subscription ID>, cred, nil)
|
||||
```
|
||||
|
||||
You can use `ClientOptions` in package `github.com/Azure/azure-sdk-for-go/sdk/azcore/arm` to set endpoint to connect with public and sovereign clouds as well as Azure Stack. For more information, please see the documentation for `azcore` at [pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore).
|
||||
|
||||
```go
|
||||
options := arm.ClientOptions {
|
||||
ClientOptions: azcore.ClientOptions {
|
||||
Cloud: cloud.AzureChina,
|
||||
},
|
||||
}
|
||||
clientFactory, err := armkeyvault.NewClientFactory(<subscription ID>, cred, &options)
|
||||
```
|
||||
|
||||
## Clients
|
||||
|
||||
A client groups a set of related APIs, providing access to its functionality. Create one or more clients to access the APIs you require using client factory.
|
||||
|
||||
```go
|
||||
client := clientFactory.NewVaultsClient()
|
||||
```
|
||||
|
||||
## Fakes
|
||||
|
||||
The fake package contains types used for constructing in-memory fake servers used in unit tests.
|
||||
This allows writing tests to cover various success/error conditions without the need for connecting to a live service.
|
||||
|
||||
Please see https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/samples/fakes for details and examples on how to use fakes.
|
||||
|
||||
## More sample code
|
||||
|
||||
- [Key](https://aka.ms/azsdk/go/mgmt/samples?path=sdk/resourcemanager/keyvault/key)
|
||||
- [Secret](https://aka.ms/azsdk/go/mgmt/samples?path=sdk/resourcemanager/keyvault/secret)
|
||||
- [Vault](https://aka.ms/azsdk/go/mgmt/samples?path=sdk/resourcemanager/keyvault/vault)
|
||||
|
||||
## Provide Feedback
|
||||
|
||||
If you encounter bugs or have suggestions, please
|
||||
[open an issue](https://github.com/Azure/azure-sdk-for-go/issues) and assign the `Key Vault` label.
|
||||
|
||||
# Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require
|
||||
you to agree to a Contributor License Agreement (CLA) declaring that you have
|
||||
the right to, and actually do, grant us the rights to use your contribution.
|
||||
For details, visit [https://cla.microsoft.com](https://cla.microsoft.com).
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether
|
||||
you need to provide a CLA and decorate the PR appropriately (e.g., label,
|
||||
comment). Simply follow the instructions provided by the bot. You will only
|
||||
need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the
|
||||
[Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information, see the
|
||||
[Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any
|
||||
additional questions or comments.
|
6
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/assets.json
сгенерированный
поставляемый
Normal file
6
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/assets.json
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"AssetsRepo": "Azure/azure-sdk-assets",
|
||||
"AssetsRepoPrefixPath": "go",
|
||||
"TagPrefix": "go/resourcemanager/keyvault/armkeyvault",
|
||||
"Tag": "go/resourcemanager/keyvault/armkeyvault_820248387e"
|
||||
}
|
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/autorest.md
сгенерированный
поставляемый
Normal file
15
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/autorest.md
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,15 @@
|
|||
### AutoRest Configuration
|
||||
|
||||
> see https://aka.ms/autorest
|
||||
|
||||
``` yaml
|
||||
azure-arm: true
|
||||
require:
|
||||
- https://github.com/Azure/azure-rest-api-specs/blob/9ec0fcc278aa2128c4fbb2b8a1aa93432d72cce0/specification/keyvault/resource-manager/readme.md
|
||||
- https://github.com/Azure/azure-rest-api-specs/blob/9ec0fcc278aa2128c4fbb2b8a1aa93432d72cce0/specification/keyvault/resource-manager/readme.go.md
|
||||
license-header: MICROSOFT_MIT_NO_VERSION
|
||||
module-version: 1.4.0
|
||||
modelerfour:
|
||||
seal-single-value-enum-by-default: true
|
||||
tag: package-2023-07
|
||||
```
|
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/build.go
сгенерированный
поставляемый
Normal file
7
vendor/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault/build.go
сгенерированный
поставляемый
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
// This file enables 'go generate' to regenerate this specific SDK
|
||||
//go:generate pwsh ../../../../eng/scripts/build.ps1 -skipBuild -cleanGenerated -format -tidy -generate -removeUnreferencedTypes resourcemanager/keyvault/armkeyvault
|
||||
|
||||
package armkeyvault
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче