diff --git a/src/Apps/LogicApp.ts b/src/Apps/LogicApp.ts index 17cbff37..f550ddd9 100644 --- a/src/Apps/LogicApp.ts +++ b/src/Apps/LogicApp.ts @@ -1,21 +1,32 @@ -import * as logic from '@pulumi/azure-native/logic'; -import { BasicResourceArgs, DefaultResourceArgs } from '../types'; -import creator from '../Core/ResourceCreator'; -import { global } from '../Common'; -import { getCertOrderName } from '../Common/Naming'; +import * as logic from "@pulumi/azure-native/logic"; +import { BasicResourceArgs, DefaultResourceArgs } from "../types"; +import { getWorkflowName } from "../Common/Naming"; -interface Props extends BasicResourceArgs, DefaultResourceArgs {} +export type WorkflowProps = BasicResourceArgs & + DefaultResourceArgs & + Pick; -export default ({ name, ...others }: Props) => { - const n = getCertOrderName(name); +export default ({ + name, + group, + dependsOn, + ignoreChanges, + importUri, + ...others +}: WorkflowProps) => { + const n = getWorkflowName(name); - const order = creator(logic.Workflow, { - workflowName: n, - ...global.groupInfo, - ...others, - sku: '', + const workFlow = new logic.Workflow( + name, + { + workflowName: n, + ...group, + ...others, + identity: { type: logic.ManagedServiceIdentityType.SystemAssigned }, + accessControl: { actions: {} }, + }, + { dependsOn, ignoreChanges, import: importUri }, + ); - } as logic.WorkflowArgs & DefaultResourceArgs); - - return order; + return workFlow; }; diff --git a/src/AzAd/RoleAssignment.ts b/src/AzAd/RoleAssignment.ts index 1c527654..4cc8a21e 100644 --- a/src/AzAd/RoleAssignment.ts +++ b/src/AzAd/RoleAssignment.ts @@ -34,14 +34,17 @@ export const roleAssignment = ({ dependsOn, }: RoleAssignmentProps) => { const role = getRoleDefinitionByName({ roleName }); - return new native.authorization.RoleAssignment( - `${name}-${roleName.split(" ").join("")}`, - { - principalId, - principalType, - roleDefinitionId: role.id, - scope, - }, - { dependsOn }, - ); + return pulumi.output(principalId).apply((id) => { + if (!id) return undefined; + return new native.authorization.RoleAssignment( + `${name}-${roleName.split(" ").join("")}`, + { + principalId, + principalType, + roleDefinitionId: role.id, + scope, + }, + { dependsOn }, + ); + }); }; diff --git a/src/Builder/ApimBuilder.ts b/src/Builder/ApimBuilder.ts index 507a6d60..5117a563 100644 --- a/src/Builder/ApimBuilder.ts +++ b/src/Builder/ApimBuilder.ts @@ -336,12 +336,17 @@ class ApimBuilder private buildPrivateLink() { if (!this._privateLink) return; PrivateEndpoint({ - ...this.commonProps, - name: this._instanceName!, - resourceId: this._apimInstance!.id, + resourceInfo: { + resourceName: this._instanceName!, + group: this.commonProps.group, + id: this._apimInstance!.id, + }, + privateDnsZoneName: "privatelink.azure-api.net", subnetIds: this._privateLink.subnetIds, - linkServiceGroupIds: ["Gateway"], + linkServiceGroupIds: this._privateLink.type + ? [this._privateLink.type] + : ["Gateway"], dependsOn: this._apimInstance, }); } diff --git a/src/Builder/ResourceBuilder.ts b/src/Builder/ResourceBuilder.ts index 7c810d8c..72d24981 100644 --- a/src/Builder/ResourceBuilder.ts +++ b/src/Builder/ResourceBuilder.ts @@ -184,7 +184,6 @@ class ResourceBuilder if (asPrivateLink && subIds.length > 0) { createVaultPrivateLink({ - name: `${this.name}-vault`, vaultInfo: this._vaultInfo!.info(), subnetIds: subIds, }); diff --git a/src/Builder/VaultBuilder.ts b/src/Builder/VaultBuilder.ts index 1db50312..5e2e6a8c 100644 --- a/src/Builder/VaultBuilder.ts +++ b/src/Builder/VaultBuilder.ts @@ -35,7 +35,6 @@ export class VaultBuilderResults implements IVaultBuilderResults { public privateLinkTo(subnetIds: Input[]): IVaultBuilderResults { createVaultPrivateLink({ - name: `${this.vaultInfo.name}-vault`, vaultInfo: this.vaultInfo, subnetIds, }); diff --git a/src/Builder/VnetBuilder.ts b/src/Builder/VnetBuilder.ts index e5ee7526..0ab7159a 100644 --- a/src/Builder/VnetBuilder.ts +++ b/src/Builder/VnetBuilder.ts @@ -1,3 +1,4 @@ +import { ResourceInfo } from "../types"; import IpAddressPrefix, { PublicIpAddressPrefixResult, } from "../VNet/IpAddressPrefix"; @@ -12,6 +13,7 @@ import { input as inputs } from "@pulumi/azure-native/types"; import NetworkPeering from "../VNet/NetworkPeering"; import { LogInfoResults } from "../Logs/Helpers"; import VPNGateway from "../VNet/VPNGateway"; +import PrivateDnsZoneBuilder from "./PrivateDnsZoneBuilder"; import { BastionCreationProps, FirewallCreationProps, @@ -27,6 +29,7 @@ import { VnetBuilderResults, VpnGatewayCreationProps, BuilderProps, + VnetPrivateDnsBuilderFunc, } from "./types"; import { getVnetInfo, parseVnetInfoFromId } from "../VNet/Helper"; import Bastion from "../VNet/Bastion"; @@ -51,6 +54,8 @@ class VnetBuilder private _peeringProps: PeeringProps[] = []; private _logInfo: LogInfoResults | undefined = undefined; private _ipType: "prefix" | "individual" = "prefix"; + private _privateDns: Record = + {}; /** The Instances */ private _ipAddressInstance: PublicIpAddressPrefixResult | undefined = @@ -60,6 +65,7 @@ class VnetBuilder private _natGatewayInstance: network.NatGateway | undefined = undefined; private _vnpGatewayInstance: network.VirtualNetworkGateway | undefined = undefined; + private _privateDnsInstances: Record = {}; constructor(commonProps: BuilderProps) { super(commonProps); @@ -122,6 +128,13 @@ class VnetBuilder this._enableRoute = true; return this; } + public withPrivateDns( + domain: string, + builder?: VnetPrivateDnsBuilderFunc, + ): IVnetBuilder { + this._privateDns[domain] = builder; + return this; + } public peeringTo(props: PeeringProps): IVnetBuilder { this._peeringProps.push(props); @@ -134,20 +147,6 @@ class VnetBuilder } /** Builders methods */ - // private validate() { - // if (this._firewallProps) { - // if (!this._firewallProps.sku) - // this._firewallProps.sku = this._natGatewayEnabled - // ? { tier: "Basic", name: "AZFW_VNet" } - // : { tier: "Basic", name: "AZFW_VNet" }; - // - // // if (this._natGatewayEnabled && this._firewallProps.sku.tier === "Basic") - // // throw new Error( - // // 'The Firewall tier "Basic" is not support Nat Gateway.', - // // ); - // } - // } - private buildIpAddress() { const ipNames = []; @@ -316,6 +315,22 @@ class VnetBuilder }); } + private buildPrivateDns() { + Object.keys(this._privateDns).forEach((k) => { + const bFunc = this._privateDns[k]; + const builder = PrivateDnsZoneBuilder({ + ...this.commonProps, + name: k, + }).linkTo({ + vnetIds: [this._vnetInstance!.id], + registrationEnabled: false, + }); + + if (bFunc) bFunc(builder); + this._privateDnsInstances[k] = builder.build(); + }); + } + private buildPeering() { if (!this._peeringProps || !this._vnetInstance) return; @@ -348,6 +363,7 @@ class VnetBuilder this.buildFirewall(); this.buildVpnGateway(); this.buildBastion(); + this.buildPrivateDns(); this.buildPeering(); return { diff --git a/src/Builder/types/apimBuilder.ts b/src/Builder/types/apimBuilder.ts index 953dc995..7e66a8dc 100644 --- a/src/Builder/types/apimBuilder.ts +++ b/src/Builder/types/apimBuilder.ts @@ -1,7 +1,7 @@ import { SkuType } from "@pulumi/azure-native/apimanagement"; import { Input } from "@pulumi/pulumi"; import { IBuilder } from "./genericBuilder"; -import { ResourceInfo } from "../../types"; +import { PrivateLinkPropsType, ResourceInfo } from "../../types"; import { AppInsightInfo } from "../../Logs/Helpers"; export type ApimSkuBuilderType = { @@ -40,8 +40,7 @@ export type ApimVnetType = { * */ type: "External" | "Internal"; }; -export type ApimPrivateLinkType = { - subnetIds: Input[]; +export type ApimPrivateLinkType = PrivateLinkPropsType & { disablePublicAccess?: boolean; }; export type ApimAuthType = { diff --git a/src/Builder/types/vnetBuilder.ts b/src/Builder/types/vnetBuilder.ts index 0597a5bb..75ee61df 100644 --- a/src/Builder/types/vnetBuilder.ts +++ b/src/Builder/types/vnetBuilder.ts @@ -10,6 +10,7 @@ import { VpnGatewayProps } from "../../VNet/VPNGateway"; import { CustomSecurityRuleArgs, RouteArgs } from "../../VNet/types"; import { LogInfoResults } from "../../Logs/Helpers"; import { PublicIpAddressPrefixResult } from "../../VNet/IpAddressPrefix"; +import { IPrivateDnsZoneBuilder } from "./privateDnsZoneBuilder"; //VNet Builder Types export type VnetBuilderResults = VnetResult & { @@ -45,6 +46,10 @@ export type VpnGatewayCreationProps = Pick< "sku" | "vpnClientAddressPools" > & { subnetSpace: string }; +export type VnetPrivateDnsBuilderFunc = ( + builder: IPrivateDnsZoneBuilder, +) => IPrivateDnsZoneBuilder; + //Starting Interface export interface IVnetBuilderStart { asHub(props?: VnetBuilderProps): IPublicIpBuilder; @@ -64,9 +69,13 @@ export interface IGatewayFireWallBuilder extends IFireWallOrVnetBuilder { export interface IVnetBuilder extends IBuilder { withBastion(props: BastionCreationProps): IVnetBuilder; - peeringTo(props: PeeringProps): IVnetBuilder; + withPrivateDns( + domain: string, + builder?: VnetPrivateDnsBuilderFunc, + ): IVnetBuilder; withSecurityRules(rules: CustomSecurityRuleArgs[]): IVnetBuilder; withRouteRules(rules: RouteArgs[]): IVnetBuilder; withLogInfo(info: LogInfoResults): IVnetBuilder; withVpnGateway(props: VpnGatewayCreationProps): IVnetBuilder; + peeringTo(props: PeeringProps): IVnetBuilder; } diff --git a/src/Common/AzureEnv.ts b/src/Common/AzureEnv.ts index cf878e0f..5cce4650 100644 --- a/src/Common/AzureEnv.ts +++ b/src/Common/AzureEnv.ts @@ -1,9 +1,8 @@ import * as pulumi from "@pulumi/pulumi"; import { authorization } from "@pulumi/azure-native"; import { registerAutoTags } from "./AutoTags"; -import { KeyVaultInfo, ResourceGroupInfo } from "../types"; +import { KeyVaultInfo, ResourceGroupInfo, ResourceInfoArg } from "../types"; import { getKeyVaultName, getResourceGroupName } from "./Naming"; -import { ResourceInfoArg } from "./ResourceEnv"; import { organization, projectName, stack } from "./StackEnv"; import { getCountryCode, getRegionCode } from "./Location"; diff --git a/src/Common/Helpers.ts b/src/Common/Helpers.ts index b7838aa3..7545438d 100644 --- a/src/Common/Helpers.ts +++ b/src/Common/Helpers.ts @@ -8,7 +8,7 @@ export function replaceAll(value: string, search: string, replace: string) { } export const toBase64 = (value: string) => - Buffer.from(value).toString('base64'); + Buffer.from(value).toString("base64"); export const shallowEquals = (obj1: any, obj2: any) => Object.keys(obj1).length === Object.keys(obj2).length && @@ -16,14 +16,53 @@ export const shallowEquals = (obj1: any, obj2: any) => /** Get Domain from Url*/ export const getDomainFromUrl = (url: string) => - url.replace('https://', '').replace('http://', '').split('/')[0]; + url.replace("https://", "").replace("http://", "").split("/")[0]; /** Get Root Domain from Url or Sub domain*/ export const getRootDomainFromUrl = (url: string) => { - const array = getDomainFromUrl(url).split('.'); - return array.slice(Math.max(array.length - 2, 0)).join('.'); + const array = getDomainFromUrl(url).split("."); + return array.slice(Math.max(array.length - 2, 0)).join("."); }; /** Create Range*/ export const RangeOf = (length: number) => Array.from({ length: length }, (v, k) => k); + +/** + * Simple object check. + * @param item + * @returns {boolean} + */ +export function isObject(item: any): boolean { + return item !== null && typeof item === "object" && !Array.isArray(item); +} + +/** + * Deep merge two or more objects. + * @param target + * @param sources + * @returns {T} + */ +export function mergeDeep(target: T, ...sources: any[]): T { + if (!sources.length) return target; + + for (const source of sources) { + if (isObject(source)) { + for (const key of Object.keys(source)) { + const sourceValue = source[key]; + const targetValue = (target as any)[key]; + + if (isObject(sourceValue)) { + if (!targetValue) { + (target as any)[key] = {}; + } + mergeDeep((target as any)[key], sourceValue); + } else { + (target as any)[key] = sourceValue; + } + } + } + } + + return target; +} diff --git a/src/Common/Naming/index.ts b/src/Common/Naming/index.ts index 3762b830..91cdca20 100644 --- a/src/Common/Naming/index.ts +++ b/src/Common/Naming/index.ts @@ -4,8 +4,12 @@ import { getResourceName } from "../ResourceEnv"; import { organization, stack } from "../StackEnv"; /** The method to get Resource group Name*/ -export const getResourceGroupName = (name: string): string => +export const getResourceGroupName = ( + name: string, + convention: ConventionProps = {}, +): string => getResourceName(name, { + ...convention, suffix: organization ? `grp-${organization}` : "grp", }); @@ -19,8 +23,8 @@ export const getStorageName = (name: string): string => { /** Get Vault Secret Name. Remove the stack name and replace all _ with - then lower cases. */ export const getSecretName = (name: string) => { - name = name.replace(`${stack}-`, ""); - name = name.replace(stack, ""); + name = replaceAll(name, `${stack}-`, ""); + name = replaceAll(name, stack, ""); name = replaceAll(name, " ", "-"); name = replaceAll(name, ".", "-"); return replaceAll(name, "_", "-").toLowerCase(); @@ -142,8 +146,8 @@ export const getNICName = (name: string) => export const getVpnName = (name: string) => getResourceName(name, { suffix: "vpn" }); -export const getVnetName = (name: string) => - getResourceName(name, { suffix: "vnt" }); +export const getVnetName = (name: string, convention: ConventionProps = {}) => + getResourceName(name, { ...convention, suffix: "vnt" }); export const getWanName = (name: string) => getResourceName(name, { suffix: "wan" }); @@ -160,6 +164,9 @@ export const getRouteName = (name: string) => export const getRouteItemName = (name: string) => getResourceName(name, { suffix: "", includeOrgName: false }); +export const getWorkflowName = (name: string) => + getResourceName(name, { suffix: "wkp" }); + export const getNetworkSecurityGroupName = (name: string) => getResourceName(name, { suffix: "nsg" }); diff --git a/src/Common/ResourceEnv.ts b/src/Common/ResourceEnv.ts index 26b6e8d6..bc0bafe7 100644 --- a/src/Common/ResourceEnv.ts +++ b/src/Common/ResourceEnv.ts @@ -1,54 +1,45 @@ +import { currentCountryCode } from "./AzureEnv"; import { replaceAll } from "./Helpers"; -import { ConventionProps, ResourceGroupInfo } from "../types"; -import { Input } from "@pulumi/pulumi"; +import { ConventionProps } from "../types"; import { organization, stack } from "./StackEnv"; -import { currentCountryCode } from "./AzureEnv"; - -export const resourceConvention: ConventionProps = { - prefix: stack, - includeRegion: true, - suffix: undefined, //This may be specified by each resource name -}; /** ==================== Resources Variables ========================= */ const getName = (name: string, convention: ConventionProps): string => { + if (convention.prefix === undefined) convention.prefix = stack; + if (convention.region === undefined) convention.region = currentCountryCode; + //console.log(convention); + if (!name) return name; - name = replaceAll(name, " ", "-"); + name = replaceAll(name, " ", "-").toLowerCase(); + const rs: string[] = []; + + //Add prefix + if (convention.prefix && !name.startsWith(convention.prefix.toLowerCase())) { + rs.push(convention.prefix.toLowerCase()); + } + + rs.push(name); //Organization - if (convention.includeOrgName && !name.includes(organization.toLowerCase())) - name = name + "-" + organization; + if (convention.includeOrgName && !name.includes(organization.toLowerCase())) { + rs.push(organization.toLowerCase()); + } //Region - if ( - convention.includeRegion && - !name.includes(currentCountryCode.toLowerCase()) - ) - name = name + "-" + currentCountryCode; - - //Add prefix - if (convention.prefix && !name.startsWith(convention.prefix.toLowerCase())) - name = convention.prefix + "-" + name; + if (convention.region && !name.includes(convention.region.toLowerCase())) { + rs.push(convention.region.toLowerCase()); + } //Add the suffix if (convention.suffix && !name.endsWith(convention.suffix.toLowerCase())) - name = name + "-" + convention.suffix; + rs.push(convention.suffix.toLowerCase()); - return name.toLowerCase(); + return rs.join("-"); }; /** The method to get Resource Name. This is not applicable for Azure Storage Account and CosmosDb*/ export const getResourceName = ( name: string, - convention?: ConventionProps, -): string => getName(name, { ...resourceConvention, ...convention }); - -export interface ResourceInfoArg { - /**If name and provider of the resource is not provided then the Id will be resource group Id*/ - name?: Input; - /**The provider name of the resource ex: "Microsoft.Network/virtualNetworks" or "Microsoft.Network/networkSecurityGroups"*/ - provider?: string; - group: ResourceGroupInfo; - subscriptionId?: Input; -} + convention: ConventionProps = {}, +): string => getName(name, convention); diff --git a/src/ContainerRegistry/index.ts b/src/ContainerRegistry/index.ts index 64074dcf..7a135156 100644 --- a/src/ContainerRegistry/index.ts +++ b/src/ContainerRegistry/index.ts @@ -2,7 +2,7 @@ import * as containerregistry from "@pulumi/azure-native/containerregistry"; import { DefaultResourceArgs, KeyVaultInfo, - NetworkRulesProps, + NetworkPropsType, ResourceGroupInfo, } from "../types"; import creator from "../Core/ResourceCreator"; @@ -23,7 +23,7 @@ interface Props extends DefaultResourceArgs { vaultInfo?: KeyVaultInfo; sku?: containerregistry.SkuName; /**Only support Premium sku*/ - network?: NetworkRulesProps; + network?: NetworkPropsType; } /** The Azure Container Registry will be created at the GLobal Group. @@ -68,15 +68,14 @@ export default ({ ...others, } as containerregistry.RegistryArgs & DefaultResourceArgs); - if (sku === "Premium" && network?.privateLink && network?.subnetId) { + if (sku === "Premium" && network?.privateLink) { PrivateEndpoint({ - name: getPrivateEndpointName(name), - group, + resourceInfo: { resourceName: name, group, id: resource.id }, privateDnsZoneName: "privatelink.azurecr.io", - subnetIds: [network.subnetId], - ...network.privateLink, - linkServiceGroupIds: ["azurecr"], - resourceId: resource.id, + subnetIds: network.privateLink.subnetIds, + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["azurecr"], }); } diff --git a/src/KeyVault/index.ts b/src/KeyVault/index.ts index bf6bab19..eb60e688 100644 --- a/src/KeyVault/index.ts +++ b/src/KeyVault/index.ts @@ -1,42 +1,34 @@ import * as keyvault from "@pulumi/azure-native/keyvault"; import { enums } from "@pulumi/azure-native/types"; import { Input } from "@pulumi/pulumi"; -import { isPrd, tenantId } from "../Common/AzureEnv"; -import { getKeyVaultName, getPrivateEndpointName } from "../Common/Naming"; +import { tenantId } from "../Common/AzureEnv"; +import { getKeyVaultName } from "../Common/Naming"; import { createDiagnostic } from "../Logs/Helpers"; import { BasicMonitorArgs, KeyVaultInfo, - PrivateLinkProps, - ResourceGroupInfo, + NetworkPropsType, + PrivateLinkPropsType, } from "../types"; import PrivateEndpoint from "../VNet/PrivateEndpoint"; import { BasicResourceArgs } from "../types"; export interface KeyVaultProps extends BasicResourceArgs { softDeleteRetentionInDays?: Input; - network?: { - //allowsAzureService?: boolean; - ipAddresses?: Array>; - subnetIds?: Array>; - }; + network?: NetworkPropsType; } export const createVaultPrivateLink = ({ - name, vaultInfo, ...props -}: PrivateLinkProps & { - name: string; +}: PrivateLinkPropsType & { vaultInfo: KeyVaultInfo; }) => PrivateEndpoint({ - name: getPrivateEndpointName(name), + resourceInfo: { ...vaultInfo, resourceName: vaultInfo.name }, ...props, - group: vaultInfo.group, - resourceId: vaultInfo.id, privateDnsZoneName: "privatelink.vaultcore.azure.net", - linkServiceGroupIds: ["keyVault"], + linkServiceGroupIds: props.type ? [props.type] : ["keyVault"], }); export const createVaultDiagnostic = ({ @@ -95,8 +87,8 @@ export default ({ ? network.ipAddresses.map((i) => ({ value: i })) : [], - virtualNetworkRules: network?.subnetIds - ? network.subnetIds.map((s) => ({ id: s })) + virtualNetworkRules: network?.subnetId + ? [{ id: network.subnetId }] : undefined, }, }, @@ -120,14 +112,19 @@ export default ({ id: vault.id, }); + // Create Private Link + const createPrivateLink = (props: PrivateLinkPropsType) => + createVaultPrivateLink({ vaultInfo: info(), ...props }); + + //Create Private Link + if (network?.privateLink) { + createPrivateLink(network!.privateLink); + } + //Add Diagnostic const addDiagnostic = (logInfo: BasicMonitorArgs) => createVaultDiagnostic({ vaultInfo: info(), logInfo }); - // Create Private Link - const createPrivateLink = (props: PrivateLinkProps) => - createVaultPrivateLink({ name, vaultInfo: info(), ...props }); - return { name: vaultName, vault, diff --git a/src/MySql/index.ts b/src/MySql/index.ts index 9d643ad4..3087b55f 100644 --- a/src/MySql/index.ts +++ b/src/MySql/index.ts @@ -1,4 +1,5 @@ -import { BasicResourceArgs, KeyVaultInfo } from "../types"; +import * as azure from "@pulumi/azure-native"; +import { BasicResourceArgs, KeyVaultInfo, NetworkPropsType } from "../types"; import { getMySqlName } from "../Common/Naming"; import * as pulumi from "@pulumi/pulumi"; import * as dbformysql from "@pulumi/azure-native/dbformysql"; @@ -11,6 +12,7 @@ import { EnvRolesResults } from "../AzAd/EnvRoles"; import { getEncryptionKeyOutput } from "../KeyVault/Helper"; import UserAssignedIdentity from "../AzAd/UserAssignedIdentity"; import { RandomString } from "@pulumi/random"; +import { convertToIpRange } from "../VNet/Helper"; import PrivateEndpoint from "../VNet/PrivateEndpoint"; import Locker from "../Core/Locker"; @@ -26,15 +28,8 @@ export interface MySqlProps extends BasicResourceArgs { version?: dbformysql.ServerVersion; storageSizeGB?: number; databases?: Array; - network?: { + network?: NetworkPropsType & { allowsPublicAccess?: boolean; - privateLink?: { - subnetId: pulumi.Input; - }; - firewallRules?: Array<{ - startIpAddress: string; - endIpAddress: string; - }>; }; } @@ -159,15 +154,18 @@ export default ({ } if (network) { - if (network.firewallRules) { - network.firewallRules.map( - (f, i) => - new dbformysql.FirewallRule(`${name}-firewall-${i}`, { - firewallRuleName: `${name}-firewall-${i}`, - serverName: mySql.name, - ...group, - ...f, - }), + if (network.ipAddresses) { + pulumi.output(network.ipAddresses).apply((ips) => + convertToIpRange(ips).map( + (f, i) => + new azure.dbforpostgresql.FirewallRule(`${name}-firewall-${i}`, { + firewallRuleName: `${name}-firewall-${i}`, + serverName: mySql.name, + ...group, + startIpAddress: f.start, + endIpAddress: f.end, + }), + ), ); } @@ -182,12 +180,12 @@ export default ({ if (network.privateLink) { PrivateEndpoint({ - name, - group, - resourceId: mySql.id, + resourceInfo: { resourceName: name, group, id: mySql.id }, privateDnsZoneName: "mysql.database.azure.com", - linkServiceGroupIds: ["mysql"], - subnetIds: [network.privateLink.subnetId], + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["mysql"], + subnetIds: network.privateLink.subnetIds, }); } } diff --git a/src/Postgresql/index.ts b/src/Postgresql/index.ts index 16a605d3..a13bd8f1 100644 --- a/src/Postgresql/index.ts +++ b/src/Postgresql/index.ts @@ -1,4 +1,4 @@ -import { BasicResourceArgs, KeyVaultInfo } from "../types"; +import { BasicResourceArgs, KeyVaultInfo, NetworkPropsType } from "../types"; import { getPostgresqlName } from "../Common/Naming"; import * as pulumi from "@pulumi/pulumi"; import * as azure from "@pulumi/azure-native"; @@ -7,6 +7,7 @@ import { randomPassword } from "../Core/Random"; import * as inputs from "@pulumi/azure-native/types/input"; import { addCustomSecret } from "../KeyVault/CustomHelper"; import { RandomString } from "@pulumi/random"; +import { convertToIpRange } from "../VNet/Helper"; import PrivateEndpoint from "../VNet/PrivateEndpoint"; import Locker from "../Core/Locker"; @@ -20,15 +21,8 @@ export interface PostgresProps extends BasicResourceArgs { version?: azure.dbforpostgresql.ServerVersion; storageSizeGB?: number; databases?: Array; - network?: { + network?: NetworkPropsType & { allowsPublicAccess?: boolean; - privateLink?: { - subnetId: pulumi.Input; - }; - firewallRules?: Array<{ - startIpAddress: string; - endIpAddress: string; - }>; }; lock?: true; } @@ -110,15 +104,18 @@ export default ({ } if (network) { - if (network.firewallRules) { - network.firewallRules.map( - (f, i) => - new azure.dbforpostgresql.FirewallRule(`${name}-firewall-${i}`, { - firewallRuleName: `${name}-firewall-${i}`, - serverName: postgres.name, - ...group, - ...f, - }), + if (network.ipAddresses) { + pulumi.output(network.ipAddresses).apply((ips) => + convertToIpRange(ips).map( + (f, i) => + new azure.dbforpostgresql.FirewallRule(`${name}-firewall-${i}`, { + firewallRuleName: `${name}-firewall-${i}`, + serverName: postgres.name, + ...group, + startIpAddress: f.start, + endIpAddress: f.end, + }), + ), ); } @@ -133,12 +130,12 @@ export default ({ if (network.privateLink) { PrivateEndpoint({ - name, - group, - resourceId: postgres.id, + resourceInfo: { resourceName: name, group, id: postgres.id }, privateDnsZoneName: "postgres.database.azure.com", - linkServiceGroupIds: ["postgresql"], - subnetIds: [network.privateLink.subnetId], + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["postgresql"], + subnetIds: network.privateLink.subnetIds, }); } } diff --git a/src/RedisCache/index.ts b/src/RedisCache/index.ts index 5079780e..e27dffd0 100644 --- a/src/RedisCache/index.ts +++ b/src/RedisCache/index.ts @@ -1,68 +1,80 @@ -import * as native from '@pulumi/azure-native'; -import * as pulumi from '@pulumi/pulumi'; +import * as cache from "@pulumi/azure-native/cache"; +import * as pulumi from "@pulumi/pulumi"; -import { BasicResourceArgs, KeyVaultInfo } from '../types'; +import { BasicResourceArgs, KeyVaultInfo, NetworkPropsType } from "../types"; -import { ToWords } from 'to-words'; -import { convertToIpRange } from '../VNet/Helper'; -import { getRedisCacheName } from '../Common/Naming'; -import { isPrd } from '../Common/AzureEnv'; -import { addCustomSecret } from '../KeyVault/CustomHelper'; +import { ToWords } from "to-words"; +import { convertToIpRange } from "../VNet/Helper"; +import { getRedisCacheName } from "../Common/Naming"; +import { isPrd } from "../Common/AzureEnv"; +import { addCustomSecret } from "../KeyVault/CustomHelper"; +import privateEndpointCreator from "../VNet/PrivateEndpoint"; const toWord = new ToWords(); interface Props extends BasicResourceArgs { vaultInfo?: KeyVaultInfo; - allowsIpAddresses?: string[]; - sku?: native.types.input.cache.SkuArgs; + network?: NetworkPropsType; + sku?: { + name: cache.SkuName | string; + family: cache.SkuFamily | string; + capacity: number; + }; } export default ({ name, group, - allowsIpAddresses, + network, vaultInfo, - sku = { name: 'Basic', family: 'C', capacity: 0 }, + sku = { name: "Basic", family: "C", capacity: 0 }, }: Props) => { name = getRedisCacheName(name); - const redis = new native.cache.Redis(name, { + const redis = new cache.Redis(name, { name, ...group, - minimumTlsVersion: '1.2', + minimumTlsVersion: "1.2", + enableNonSslPort: false, + identity: { type: cache.ManagedServiceIdentityType.SystemAssigned }, sku, - zones: isPrd && sku.name === 'Premium' ? ['1', '2', '3'] : undefined, + zones: isPrd && sku.name === "Premium" ? ["1", "2", "3"] : undefined, + subnetId: network?.subnetId, + publicNetworkAccess: network?.privateLink ? "Disabled" : "Enabled", }); - // new native.cache.PatchSchedule( - // name, - // { - // name: 'default', - // ...group, - // scheduleEntries: [ - // { dayOfWeek: 'Everyday', startHourUtc: 0, maintenanceWindow: 'PT5H' }, - // ], - // }, - // { dependsOn: redis } - // ); - - if (allowsIpAddresses) { - convertToIpRange(allowsIpAddresses).map((range, i) => { - const n = `allow_Ip_${toWord.convert(i)}`.toLowerCase(); - return new native.cache.FirewallRule(n, { - ruleName: n, - cacheName: redis.name, - ...group, - startIP: range.start, - endIP: range.end, + //Whitelist IpAddress + if (network?.ipAddresses) { + pulumi.output(network.ipAddresses).apply((ips) => { + convertToIpRange(ips).map((range, i) => { + const n = `allow_Ip_${toWord.convert(i)}`.toLowerCase(); + return new cache.FirewallRule(n, { + ruleName: n, + cacheName: redis.name, + ...group, + startIP: range.start, + endIP: range.end, + }); }); }); } + //Private Link + if (network?.privateLink) { + privateEndpointCreator({ + resourceInfo: { resourceName: name, group, id: redis.id }, + privateDnsZoneName: "privatelink.redis.cache.windows.net", + subnetIds: network.privateLink.subnetIds, + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["redisCache"], + }); + } + if (vaultInfo) { pulumi.all([redis.name, redis.hostName]).apply(async ([n, h]) => { if (!h) return; - const keys = await native.cache.listRedisKeys({ + const keys = await cache.listRedisKeys({ name: n, resourceGroupName: group.resourceGroupName, }); @@ -71,28 +83,28 @@ export default ({ name: `${name}-primary-key`, value: keys.primaryKey, vaultInfo, - contentType: 'Redis Cache', + contentType: "Redis Cache", }); addCustomSecret({ name: `${name}-secondary-key`, value: keys.secondaryKey, vaultInfo, - contentType: 'Redis Cache', + contentType: "Redis Cache", }); addCustomSecret({ name: `${name}-primary-connection`, value: `${name}.redis.cache.windows.net:6380,password=${keys.primaryKey},ssl=True,abortConnect=False`, vaultInfo, - contentType: 'Redis Cache', + contentType: "Redis Cache", }); addCustomSecret({ name: `${name}-secondary-connection`, value: `${name}.redis.cache.windows.net:6380,password=${keys.secondaryKey},ssl=True,abortConnect=False`, vaultInfo, - contentType: 'Redis Cache', + contentType: "Redis Cache", }); }); } diff --git a/src/ServiceBus/index.ts b/src/ServiceBus/index.ts index dbddd494..161eefb1 100644 --- a/src/ServiceBus/index.ts +++ b/src/ServiceBus/index.ts @@ -7,7 +7,7 @@ import { BasicResourceResultProps, DefaultResourceArgs, KeyVaultInfo, - PrivateLinkProps, + NetworkPropsType, ResourceGroupInfo, } from "../types"; import { @@ -462,11 +462,7 @@ interface Props alternateName: pulumi.Input; partnerNamespace: pulumi.Input; }; - network?: { - whitelistIps?: Array>; - enablePrivateLink?: boolean; - subnetId?: pulumi.Input; - }; + network?: NetworkPropsType; monitoring?: BasicMonitorArgs; sku?: bus.SkuName; vaultInfo?: KeyVaultInfo; @@ -591,17 +587,14 @@ export default ({ } if (network && sku === bus.SkuName.Premium) { - if ( - !network.enablePrivateLink && - (network.subnetId || network.whitelistIps) - ) { + if (network.subnetId || network.ipAddresses) { new bus.NamespaceNetworkRuleSet(name, { namespaceName: namespace.name, ...group, defaultAction: "Deny", - ipRules: network.whitelistIps - ? network.whitelistIps.map((i) => ({ + ipRules: network.ipAddresses + ? network.ipAddresses.map((i) => ({ ipMask: i, action: bus.NetworkRuleIPAction.Allow, })) @@ -616,14 +609,15 @@ export default ({ ] : undefined, }); - } else if (network.enablePrivateLink && network.subnetId) { + } + + if (network.privateLink) { PrivateEndpoint({ - name: getPrivateEndpointName(name), - group, - subnetIds: [network.subnetId], - //useGlobalDnsZone: network.useGlobalDnsZone, - resourceId: namespace.id, - linkServiceGroupIds: ["namespace"], + resourceInfo: { resourceName: name, group, id: namespace.id }, + subnetIds: network.privateLink.subnetIds, + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["namespace"], privateDnsZoneName: "privatelink.servicebus.windows.net", }); } diff --git a/src/SignalR/index.ts b/src/SignalR/index.ts index 8bcde485..f462c4b3 100644 --- a/src/SignalR/index.ts +++ b/src/SignalR/index.ts @@ -2,7 +2,11 @@ import * as native from "@pulumi/azure-native"; import * as pulumi from "@pulumi/pulumi"; import { isDev } from "../Common/AzureEnv"; import { getPrivateEndpointName, getSignalRName } from "../Common/Naming"; -import { BasicResourceArgs, KeyVaultInfo, PrivateLinkProps } from "../types"; +import { + BasicResourceArgs, + KeyVaultInfo, + PrivateLinkPropsType, +} from "../types"; import PrivateEndpoint from "../VNet/PrivateEndpoint"; import { addCustomSecret } from "../KeyVault/CustomHelper"; @@ -15,7 +19,7 @@ interface ResourceSkuArgs { interface Props extends BasicResourceArgs { vaultInfo?: KeyVaultInfo; allowedOrigins?: pulumi.Input[]>; - privateLink?: PrivateLinkProps; + privateLink?: PrivateLinkPropsType; kind?: native.signalrservice.ServiceKind; sku?: pulumi.Input; } @@ -33,7 +37,6 @@ export default ({ }, allowedOrigins, }: Props) => { - const privateEndpointName = getPrivateEndpointName(name); name = getSignalRName(name); const signalR = new native.signalrservice.SignalR(name, { @@ -49,27 +52,16 @@ export default ({ networkACLs: privateLink ? { defaultAction: native.signalrservice.ACLAction.Allow, - publicNetwork: isDev - ? { - allow: [ - native.signalrservice.SignalRRequestType.ClientConnection, - native.signalrservice.SignalRRequestType.ServerConnection, - native.signalrservice.SignalRRequestType.RESTAPI, - ], - //deny: [native.signalrservice.SignalRRequestType.RESTAPI], - } - : { - allow: [ - native.signalrservice.SignalRRequestType.ClientConnection, - ], - deny: [ - native.signalrservice.SignalRRequestType.ServerConnection, - native.signalrservice.SignalRRequestType.RESTAPI, - ], - }, + publicNetwork: { + allow: [native.signalrservice.SignalRRequestType.ClientConnection], + deny: [ + native.signalrservice.SignalRRequestType.ServerConnection, + native.signalrservice.SignalRRequestType.RESTAPI, + ], + }, privateEndpoints: [ { - name: privateEndpointName, + name: getPrivateEndpointName(name), allow: [ native.signalrservice.SignalRRequestType.ClientConnection, native.signalrservice.SignalRRequestType.ServerConnection, @@ -78,19 +70,26 @@ export default ({ }, ], } - : undefined, + : { + defaultAction: native.signalrservice.ACLAction.Allow, + publicNetwork: { + allow: [ + native.signalrservice.SignalRRequestType.ClientConnection, + native.signalrservice.SignalRRequestType.ServerConnection, + native.signalrservice.SignalRRequestType.RESTAPI, + ], + }, + }, sku, }); if (privateLink) { //The Private Zone will create in Dev and reuse for sandbox and prd. PrivateEndpoint({ - name: privateEndpointName, - group, + resourceInfo: { resourceName: name, group, id: signalR.id }, privateDnsZoneName: "privatelink.service.signalr.net", - ...privateLink, + subnetIds: privateLink.subnetIds, linkServiceGroupIds: ["signalr"], - resourceId: signalR.id, }); } diff --git a/src/Sql/index.ts b/src/Sql/index.ts index f40d4c99..710fca3d 100644 --- a/src/Sql/index.ts +++ b/src/Sql/index.ts @@ -9,6 +9,7 @@ import { BasicResourceArgs, BasicResourceResultProps, KeyVaultInfo, + NetworkPropsType, ResourceInfo, } from "../types"; import { convertToIpRange } from "../VNet/Helper"; @@ -67,13 +68,9 @@ export type SqlAuthType = { password: Input; }; -export type SqlNetworkType = { +export type SqlNetworkType = NetworkPropsType & { //Enable this will add 0.0.0.0 to 255.255.255.255 to the DB whitelist acceptAllPublicConnect?: boolean; - subnetId?: Input; - ipAddresses?: Input[]; - /** To enable Private Link need to ensure the subnetId is provided. */ - asPrivateLink?: boolean; }; export type SqlElasticPoolType = { @@ -151,7 +148,7 @@ export default ({ sid: adminGroup?.objectId, login: adminGroup?.displayName, }, - publicNetworkAccess: network?.asPrivateLink + publicNetworkAccess: network?.privateLink ? sql.ServerNetworkAccessFlag.Disabled : sql.ServerNetworkAccessFlag.Enabled, }, @@ -177,27 +174,28 @@ export default ({ }) : undefined; + //Subnet if (network?.subnetId) { - if (network.asPrivateLink) { - privateEndpointCreator({ - group, - name, - resourceId: sqlServer.id, - privateDnsZoneName: "privatelink.database.windows.net", - subnetIds: [network.subnetId], - linkServiceGroupIds: ["sqlServer"], - }); - } else { - //Link to Vnet - new sql.VirtualNetworkRule(sqlName, { - virtualNetworkRuleName: `${sqlName}-vnetRule`, - serverName: sqlServer.name, - ...group, + //Link to Vnet + new sql.VirtualNetworkRule(sqlName, { + virtualNetworkRuleName: `${sqlName}-vnetRule`, + serverName: sqlServer.name, + ...group, - virtualNetworkSubnetId: network.subnetId, - ignoreMissingVnetServiceEndpoint: false, - }); - } + virtualNetworkSubnetId: network.subnetId, + ignoreMissingVnetServiceEndpoint: false, + }); + } + //Private Link + if (network?.privateLink) { + privateEndpointCreator({ + resourceInfo: { resourceName: name, group, id: sqlServer.id }, + privateDnsZoneName: "privatelink.database.windows.net", + subnetIds: network.privateLink.subnetIds, + linkServiceGroupIds: network.privateLink.type + ? [network.privateLink.type] + : ["sqlServer"], + }); } //Allow Public Ip Accessing @@ -237,7 +235,6 @@ export default ({ }); } - //Default Alert Policy //ServerSecurityAlertPolicy const alertPolicy = new sql.ServerSecurityAlertPolicy( name, @@ -350,9 +347,9 @@ export default ({ }); if (vaultInfo) { - const connectionString = auth?.adminLogin - ? interpolate`Data Source=${sqlName}.database.windows.net;Initial Catalog=${d.name};User Id=${auth.adminLogin};Password=${auth.password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=120;` - : interpolate`Data Source=${sqlName}.database.windows.net;Initial Catalog=${d.name};Authentication=Active Directory Integrated;;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=120;`; + const connectionString = auth?.azureAdOnlyAuthentication + ? interpolate`Data Source=${sqlName}.database.windows.net;Initial Catalog=${d.name};Authentication=Active Directory Integrated;;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=120;` + : interpolate`Data Source=${sqlName}.database.windows.net;Initial Catalog=${d.name};User Id=${auth.adminLogin};Password=${auth.password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=120;`; addCustomSecret({ name: d.name, diff --git a/src/Storage/index.ts b/src/Storage/index.ts index 704a8b52..fb0b0ac0 100644 --- a/src/Storage/index.ts +++ b/src/Storage/index.ts @@ -164,11 +164,9 @@ export default ({ if (network?.privateEndpoint) { //Create Private Endpoints privateEndpoint({ - name, - group, - resourceId: stg.id, + resourceInfo: { resourceName: name, group, id: stg.id }, subnetIds: network.privateEndpoint.subnetIds, - privateDnsZoneName: `${name}.privatelink.${network.privateEndpoint.type}.core.windows.net`, + privateDnsZoneName: `privatelink.${network.privateEndpoint.type}.core.windows.net`, linkServiceGroupIds: [network.privateEndpoint.type], }); } diff --git a/src/VNet/Helper.ts b/src/VNet/Helper.ts index 3128d854..0ae57afb 100644 --- a/src/VNet/Helper.ts +++ b/src/VNet/Helper.ts @@ -2,7 +2,7 @@ import * as network from "@pulumi/azure-native/network"; import { Input, interpolate, output, Output } from "@pulumi/pulumi"; import * as netmask from "netmask"; import { - currentRegionName, + currentCountryCode, parseResourceInfoFromId, subscriptionId, } from "../Common/AzureEnv"; @@ -21,10 +21,7 @@ export const azFirewallSubnet = "AzureFirewallSubnet"; export const azFirewallManagementSubnet = "AzureFirewallManagementSubnet"; export const azBastionSubnetName = "AzureBastionSubnet"; -export const getIpsRange = (prefix: string) => { - //console.debug('getIpsRange', block); - return new netmask.Netmask(prefix); -}; +export const getIpsRange = (prefix: string) => new netmask.Netmask(prefix); /** Convert IP address and IP address group into range */ export const convertToIpRange = ( @@ -87,9 +84,12 @@ export const getIpAddressResource = ({ }); }; -export const getVnetInfo = (groupName: string): VnetInfoType => { - const vnetName = getVnetName(groupName); - const rsName = getResourceGroupName(groupName); +export const getVnetInfo = ( + groupName: string, + region: string = currentCountryCode, +): VnetInfoType => { + const vnetName = getVnetName(groupName, { region }); + const rsName = getResourceGroupName(groupName, { region }); return { vnetName, @@ -98,8 +98,11 @@ export const getVnetInfo = (groupName: string): VnetInfoType => { }; }; -export const getVnetIdByName = (groupName: string) => { - const info = getVnetInfo(groupName); +export const getVnetIdByName = ( + groupName: string, + region: string = currentCountryCode, +) => { + const info = getVnetInfo(groupName, region); return interpolate`/subscriptions/${info.subscriptionId}/resourceGroups/${info.resourceGroupName}/providers/Microsoft.Network/virtualNetworks/${info.vnetName}`; }; diff --git a/src/VNet/PrivateEndpoint.ts b/src/VNet/PrivateEndpoint.ts index 84c364ce..4a0e8280 100644 --- a/src/VNet/PrivateEndpoint.ts +++ b/src/VNet/PrivateEndpoint.ts @@ -1,42 +1,45 @@ import * as network from "@pulumi/azure-native/network"; -import { Input, output } from "@pulumi/pulumi"; -import { BasicResourceArgs, PrivateLinkProps } from "../types"; -import { getVnetIdFromSubnetId } from "./Helper"; +import { output } from "@pulumi/pulumi"; +import { BasicArgs, PrivateLinkPropsType, ResourceInfo } from "../types"; import { parseResourceInfoFromId } from "../Common/AzureEnv"; import { getPrivateEndpointName } from "../Common/Naming"; import { PrivateDnsZoneBuilder } from "../Builder"; -interface Props extends BasicResourceArgs, PrivateLinkProps { - resourceId: Input; - privateDnsZoneName: string; - linkServiceGroupIds: string[]; -} +export type PrivateEndpointProps = Pick & + Pick & { + resourceInfo: ResourceInfo; + /** check the private link DNS Zone here https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-dns */ + privateDnsZoneName: string; + linkServiceGroupIds: string[]; + }; export default ({ - name, - group, - resourceId, + resourceInfo, subnetIds, privateDnsZoneName, linkServiceGroupIds, -}: Props) => { - name = getPrivateEndpointName(name); + dependsOn, +}: PrivateEndpointProps) => { + const name = getPrivateEndpointName(resourceInfo.resourceName); const endpoints = subnetIds.map( (s, index) => - new network.PrivateEndpoint(`${name}-${index}`, { - privateEndpointName: `${name}-${index}`, - ...group, - - subnet: { id: s }, - privateLinkServiceConnections: [ - { - groupIds: linkServiceGroupIds, - name: `${name}-conn`, - privateLinkServiceId: resourceId, - }, - ], - }), + new network.PrivateEndpoint( + `${name}-${index}`, + { + privateEndpointName: `${name}-${index}`, + ...resourceInfo.group, + subnet: { id: s }, + privateLinkServiceConnections: [ + { + groupIds: linkServiceGroupIds, + name: `${name}-conn`, + privateLinkServiceId: resourceInfo.id, + }, + ], + }, + { dependsOn }, + ), ); //Get IpAddress in @@ -46,11 +49,12 @@ export default ({ ), ).apply((a) => a.flatMap((i) => i!)); - output([resourceId, ipAddresses]).apply(([id, ip]) => { + output([resourceInfo.id, ipAddresses]).apply(([id, ip]) => { const resourceInfo = parseResourceInfoFromId(id as string); return PrivateDnsZoneBuilder({ name: `${resourceInfo!.name}.${privateDnsZoneName}`, - group, + group: resourceInfo!.group, + dependsOn, }) .withARecord({ ipAddresses: ip as string[], recordName: "@" }) .linkTo({ subnetIds, registrationEnabled: false }) diff --git a/src/Web/AppConfig.ts b/src/Web/AppConfig.ts index df01b817..2f38a038 100644 --- a/src/Web/AppConfig.ts +++ b/src/Web/AppConfig.ts @@ -3,7 +3,7 @@ import { isPrd } from "../Common/AzureEnv"; import { getAppConfigName, getPrivateEndpointName } from "../Common/Naming"; import { KeyVaultInfo, - PrivateLinkProps, + PrivateLinkPropsType, ResourceGroupInfo, ResourceInfo, } from "../types"; @@ -13,7 +13,7 @@ import { addCustomSecret } from "../KeyVault/CustomHelper"; export type AppConfigProps = { name: string; group: ResourceGroupInfo; - privateLink?: PrivateLinkProps; + privateLink?: PrivateLinkPropsType; disableLocalAuth?: boolean; vaultInfo: KeyVaultInfo; }; @@ -76,11 +76,9 @@ export default ({ //Private Link if (privateLink) { PrivateEndpoint({ - name: getPrivateEndpointName(name), - group, - privateDnsZoneName: `${name}.privatelink.azconfig.io`, + resourceInfo: { resourceName: name, group, id: app.id }, + privateDnsZoneName: "privatelink.azconfig.io", linkServiceGroupIds: ["appConfig"], - resourceId: app.id, ...privateLink, }); } diff --git a/src/types.ts b/src/types.ts index e615820f..da8b0956 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,6 +5,15 @@ import * as pulumi from "@pulumi/pulumi"; import { input as inputs, enums } from "@pulumi/azure-native/types"; import { EnvRoleKeyTypes } from "./AzAd/EnvRoles"; +export interface ResourceInfoArg { + /**If name and provider of the resource is not provided then the Id will be resource group Id*/ + name?: Input; + /**The provider name of the resource ex: "Microsoft.Network/virtualNetworks" or "Microsoft.Network/networkSecurityGroups"*/ + provider?: string; + group: ResourceGroupInfo; + subscriptionId?: Input; +} + export interface BasicArgs { dependsOn?: Input[]> | Input; importUri?: string; @@ -20,21 +29,11 @@ export interface ConventionProps { prefix?: string; suffix?: string; /**Whether include the Azure Region name at the end of the name or not*/ - includeRegion?: boolean; + region?: string; /**Whether include the organization name at the end of the name or not*/ includeOrgName?: boolean; } -export interface PrivateLinkProps { - subnetIds: Input[]; -} - -export interface NetworkRulesProps { - subnetId?: Input; - privateLink?: Omit; - ipAddresses?: Input[]; -} - export interface BasicMonitorArgs extends BasicArgs { logWpId?: Input; logStorageId?: Input; @@ -69,6 +68,17 @@ export interface DefaultResourceArgs extends BasicArgs { monitoring?: Omit; } +export type PrivateLinkPropsType = { + subnetIds: Input[]; + type?: string; +}; + +export type NetworkPropsType = { + subnetId?: Input; + ipAddresses?: Input[]; + privateLink?: PrivateLinkPropsType; +}; + export interface BasicResourceResultProps { name: string; resource: TClass; @@ -83,7 +93,7 @@ export interface ResourceResultProps export interface KeyVaultInfo { name: string; group: ResourceGroupInfo; - id: Input; + id: Output; } export type IdentityRoleAssignment = { diff --git a/tsconfig.json b/tsconfig.json index d1210550..d5a91880 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -53,6 +53,7 @@ "src/Builder/ApimProductBuilder.ts", "src/Builder/ApimRootBuilder.ts", "src/Builder/ApimWorkspaceBuilder.ts", + "src/Builder/CdnBuilder.ts", "src/Builder/DnsZoneBuilder.ts", "src/Builder/PrivateDnsZoneBuilder.ts", "src/Builder/ResourceBuilder.ts",