Skip to content

Commit

Permalink
Azure PowerShell Deployment Script (#92)
Browse files Browse the repository at this point in the history
* Azure PowerShell Deployment Script

* Tests and readme

* typo

* ManagedIdentity configuration static

* fixes
  • Loading branch information
fraliv13 authored Feb 12, 2024
1 parent d78c9d9 commit 7daee22
Show file tree
Hide file tree
Showing 31 changed files with 1,550 additions and 42 deletions.
6 changes: 4 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
],
"env": {
"AZURE_LOCATION": "West Europe",
"VAULT_ADDR": "http://localhost:62293/",
//"VAULT_TOKEN": "PLEASE_ADD_VAULT_TOKEN"",
"VAULT_ADDR": "http://localhost:54969/",
//"VAULT_TOKEN": "PLEASE_ADD_VAULT_TOKEN"",
"AZURE_MANAGED_IDENTITY_RG": "global",
"AZURE_MANAGED_IDENTITY_NAME": "scriptidentity",
//"RUSI_ENABLED": "true"
//"PULUMI_SKIP_REFRESH": "true",
},
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,51 @@ spec:
workspaceFriendlyName: Charisma
```

### AzurePowershellScript
`AzurePowershellScript` is a Custom Resource Definition (CRD) that represents an Azure PowerShell deployment script.

Definition can be found [here](./helm/crds/provisioning.totalsoft.ro_azurepowershellscripts.yaml)

#### Spec
The `AzurePowershellScript` spec has the following fields:

- `scriptContent`: The content of the PowerShell script to be executed.
- `scriptArguments`: The arguments to be passed to the PowerShell script. These should match the parameters defined in the scriptContent.
- `domainRef`: The reference to the domain that the user belongs to.
- `platformRef`: The reference to the platform that the user belongs to.
- `forceUpdateTag`: Update this value to trigger the script even if the content or args are unchanged

Example:
```yaml
apiVersion: provisioning.totalsoft.ro/v1alpha1
kind: AzurePowerShellScript
metadata:
name: createresourcegroup
namespace: provisioning-test
spec:
domainRef: domain2
exports:
- scriptOutputs:
toConfigMap:
keyTemplate: MultiTenancy__Tenants__{{ .Tenant.Code }}__ScriptOutputs
platformRef: provisioning.test
scriptContent: |-
param([string] $name)
$output = "RG name: {0}" -f $name
Write-Output $output
$DeploymentScriptOutputs = @{}
$DeploymentScriptOutputs['text'] = $output
New-AzResourceGroup $name "West Europe"
scriptArguments: "-name testrg-{{ .Platform }}-{{ .Tenant.Code }}"
target:
category: Tenant
```



### EntraUser

`EntraUser` is a Custom Resource Definition (CRD) that represents a user for Entra Id.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/pulumi/pulumi-azure-native-sdk/authorization/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/compute/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/desktopvirtualization/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/managedidentity/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/network/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/resources/v2 v2.4.0
github.com/pulumi/pulumi-azure-native-sdk/sql/v2 v2.4.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ github.com/pulumi/pulumi-azure-native-sdk/compute/v2 v2.4.0 h1:h6SVlNPqa8Spxya7G
github.com/pulumi/pulumi-azure-native-sdk/compute/v2 v2.4.0/go.mod h1:eD5kkSSQU2kJbW7telpS9gaM6hiRH4Q8u4lcOpx8jrc=
github.com/pulumi/pulumi-azure-native-sdk/desktopvirtualization/v2 v2.4.0 h1:pz8cmyWEFE4qfGGDBAGMQ35pWckM2OOSxgY1cK9e4JI=
github.com/pulumi/pulumi-azure-native-sdk/desktopvirtualization/v2 v2.4.0/go.mod h1:s7GSMVekCyCrWTEA3aOdVDtOVkIqTW0yrMnWlWG+4V8=
github.com/pulumi/pulumi-azure-native-sdk/managedidentity/v2 v2.4.0 h1:94XmWZiARdqexr5Sm+PW+tnxQ0VT5lRIXxrWO/WcHJQ=
github.com/pulumi/pulumi-azure-native-sdk/managedidentity/v2 v2.4.0/go.mod h1:JT+ptHaDSxTWwZYmnwKCewX8imIsBE5c49gryfOI5nY=
github.com/pulumi/pulumi-azure-native-sdk/network/v2 v2.4.0 h1:KrMG6wvPQuBEqbECNotGBWEuhEEoArN9ndcdkKIzWIY=
github.com/pulumi/pulumi-azure-native-sdk/network/v2 v2.4.0/go.mod h1:vszGWHBWdeTWzIIHR7ka04NGQh0GHyVK/yhAbtIEnA4=
github.com/pulumi/pulumi-azure-native-sdk/resources/v2 v2.4.0 h1:xqKfg8BZSQxZFrTtj06Qjjro7yyOiep58+N6hszLSJE=
Expand Down
166 changes: 166 additions & 0 deletions helm/crds/provisioning.totalsoft.ro_azurepowershellscripts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: azurepowershellscripts.provisioning.totalsoft.ro
spec:
group: provisioning.totalsoft.ro
names:
kind: AzurePowerShellScript
listKind: AzurePowerShellScriptList
plural: azurepowershellscripts
singular: azurepowershellscript
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.platformRef
name: Platform
type: string
- jsonPath: .spec.domainRef
name: Domain
type: string
name: v1alpha1
schema:
openAPIV3Schema:
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
properties:
dependsOn:
description: List of dependencies
items:
properties:
kind:
description: Kind is a string value representing the REST resource
this dependency represents.
type: string
name:
description: ' The name of the dependency.'
type: string
required:
- kind
- name
type: object
type: array
domainRef:
description: Business Domain that this resource is provision for.
type: string
exports:
description: Export provisioning values spec.
items:
properties:
domain:
description: The domain or bounded-context in which this script
will be used.
type: string
scriptOutputs:
description: Represents the outputs of the Azure PowerShell
script.
properties:
toConfigMap:
properties:
keyTemplate:
type: string
required:
- keyTemplate
type: object
toVault:
properties:
keyTemplate:
type: string
required:
- keyTemplate
type: object
type: object
type: object
type: array
forceUpdateTag:
description: Change value to force the script to execute even if it
has not changed.
type: string
platformRef:
description: Target platform (custom resource name).
type: string
scriptArguments:
description: |-
Represents the arguments to be passed to the PowerShell script.
eg: "-name JohnDoe"
type: string
scriptContent:
description: ScriptContent represents the content of an Azure PowerShell
script.
type: string
target:
default:
category: Tenant
description: The provisioning target.
properties:
category:
default: Tenant
description: 'Provisioning target type. Possible values: Tenant,
Platform'
enum:
- Tenant
- Platform
type: string
filter:
description: |-
Filter targets (applies for category "Tenant").
If ommited all targets are selected.
properties:
kind:
default: Blacklist
description: 'Includes or excludes the speciffied targets.
Possibile values: Blacklist, Whitelist'
enum:
- Blacklist
- Whitelist
type: string
values:
description: A list of targets to include or exculde
items:
type: string
type: array
required:
- kind
type: object
required:
- category
type: object
tenantOverrides:
additionalProperties:
x-kubernetes-preserve-unknown-fields: true
description: |-
Overrides for tenants. Dictionary with tenant name as key, spec override as value.
The spec override has the same structure as Spec
type: object
required:
- domainRef
- platformRef
- scriptContent
- target
type: object
required:
- spec
type: object
served: true
storage: true
subresources: {}
4 changes: 1 addition & 3 deletions helm/crds/provisioning.totalsoft.ro_entrausers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ spec:
items:
properties:
domain:
description: The domain or bounded-context in which this database
description: The domain or bounded-context in which this user
will be used.
type: string
initialPassword:
Expand Down Expand Up @@ -117,8 +117,6 @@ spec:
- keyTemplate
type: object
type: object
required:
- domain
type: object
type: array
initialPassword:
Expand Down
10 changes: 10 additions & 0 deletions helm/templates/provisioner-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ spec:
configMapKeyRef:
name: azure-config
key: tenantId
- name: AZURE_MANAGED_IDENTITY_RG
valueFrom:
configMapKeyRef:
name: azure-config
key: managedIdentityRG
- name: AZURE_MANAGED_IDENTITY_NAME
valueFrom:
configMapKeyRef:
name: azure-config
key: managedIdentityName
- name: ARM_CLIENT_ID
valueFrom:
configMapKeyRef:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package pulumi

import (
"encoding/json"
"os"

"github.com/pulumi/pulumi-azure-native-sdk/managedidentity/v2"
"github.com/pulumi/pulumi-azure-native-sdk/resources/v2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"totalsoft.ro/platform-controllers/internal/controllers/provisioning"
"totalsoft.ro/platform-controllers/internal/template"
provisioningv1 "totalsoft.ro/platform-controllers/pkg/apis/provisioning/v1alpha1"
)

func deployAzurePowerShellScript(target provisioning.ProvisioningTarget,
resourceGroupName pulumi.StringOutput,
azurePowerShellScript *provisioningv1.AzurePowerShellScript,
dependencies []pulumi.Resource,
ctx *pulumi.Context) (*resources.AzurePowerShellScript, error) {

valueExporter := handleValueExport(target)
gvk := provisioningv1.SchemeGroupVersion.WithKind("AzurePowerShellScript")

tc := provisioning.GetTemplateContext(target)

parsedArgs, err := template.ParseTemplate(azurePowerShellScript.Spec.ScriptArguments, tc)
if err != nil {
return nil, err
}

managedIdentity, err := managedidentity.LookupUserAssignedIdentity(ctx, &managedidentity.LookupUserAssignedIdentityArgs{
ResourceGroupName: os.Getenv("AZURE_MANAGED_IDENTITY_RG"),
ResourceName: os.Getenv("AZURE_MANAGED_IDENTITY_NAME"),
})

if err != nil {
return nil, err
}

script, err := resources.NewAzurePowerShellScript(ctx, azurePowerShellScript.Name, &resources.AzurePowerShellScriptArgs{
Kind: pulumi.String("AzurePowerShell"),
ForceUpdateTag: pulumi.String(azurePowerShellScript.Spec.ForceUpdateTag), // Change to force redeploying the script if desired
ResourceGroupName: resourceGroupName,
Arguments: pulumi.String(parsedArgs), // Set the arguments for the script'"),
ScriptContent: pulumi.String(azurePowerShellScript.Spec.ScriptContent),
CleanupPreference: pulumi.String("OnSuccess"), // Set the cleanup preference for the script
Timeout: pulumi.String("PT1H"), // Set an appropriate timeout for the script
Identity: &resources.ManagedServiceIdentityArgs{
Type: pulumi.String(resources.ManagedServiceIdentityTypeUserAssigned),
UserAssignedIdentities: pulumi.StringArray{
pulumi.String(managedIdentity.Id),
},
},
AzPowerShellVersion: pulumi.String("11.0"), // Specify the desired version of Az PowerShell module
RetentionInterval: pulumi.String("P1D"), // Set the retention time for the script's logs
})
if err != nil {
return nil, err
}

for _, exp := range azurePowerShellScript.Spec.Exports {
domain := exp.Domain
if domain == "" {
domain = azurePowerShellScript.Spec.DomainRef
}

err = valueExporter(newExportContext(ctx, domain, azurePowerShellScript.Name, azurePowerShellScript.ObjectMeta, gvk),

map[string]exportTemplateWithValue{"scriptOutputs": {exp.ScriptOutputs, script.Outputs.ApplyT(func(outputs map[string]interface{}) (string, error) {
outputsJson, err := json.Marshal(outputs)
if err != nil {
return "", err
}

return string(outputsJson), err
}).(pulumi.StringOutput)}})
if err != nil {
return nil, err
}
}
return script, nil
}
Loading

0 comments on commit 7daee22

Please sign in to comment.