diff --git a/provider/pkg/provider/azure/bastion.go b/provider/pkg/provider/azure/bastion.go index ae4f9ac..6bdeefa 100644 --- a/provider/pkg/provider/azure/bastion.go +++ b/provider/pkg/provider/azure/bastion.go @@ -32,6 +32,7 @@ type BastionArgs struct { EnableSSH bool `pulumi:"enableSSH"` EnableExitNode bool `pulumi:"enableExitNode"` EnableAppConnector bool `pulumi:"enableAppConnector"` + Public bool `pulumi:"public"` } type UserDataArgs struct { @@ -88,7 +89,7 @@ func NewBastion(ctx *pulumi.Context, data := pulumi.All(tailnetKey.Key, args.Routes, args.TailscaleTags, args.EnableSSH, hostname, args.EnableExitNode, args.EnableAppConnector).ApplyT( func(args []interface{}) (string, error) { - tagCSV := strings.Join(args[3].([]string), ",") + tagCSV := strings.Join(args[2].([]string), ",") var routesCsv string @@ -149,6 +150,17 @@ func NewBastion(ctx *pulumi.Context, size = 1 } + var publicIPConfig compute.LinuxVirtualMachineScaleSetNetworkInterfaceIpConfigurationPublicIpAddressArray + + if args.Public { + + publicIPConfig = compute.LinuxVirtualMachineScaleSetNetworkInterfaceIpConfigurationPublicIpAddressArray{ + &compute.LinuxVirtualMachineScaleSetNetworkInterfaceIpConfigurationPublicIpAddressArgs{ + Name: pulumi.String("public"), + }, + } + } + scaleset, err := compute.NewLinuxVirtualMachineScaleSet(ctx, name, &compute.LinuxVirtualMachineScaleSetArgs{ ResourceGroupName: args.ResourceGroupName, Location: args.Location, @@ -183,9 +195,10 @@ func NewBastion(ctx *pulumi.Context, EnableIpForwarding: pulumi.Bool(true), IpConfigurations: &compute.LinuxVirtualMachineScaleSetNetworkInterfaceIpConfigurationArray{ &compute.LinuxVirtualMachineScaleSetNetworkInterfaceIpConfigurationArgs{ - Name: pulumi.String("internal"), - Primary: pulumi.Bool(true), - SubnetId: args.SubnetID, + Name: pulumi.String("internal"), + Primary: pulumi.Bool(true), + SubnetId: args.SubnetID, + PublicIpAddresses: publicIPConfig, }, }, }, @@ -195,6 +208,9 @@ func NewBastion(ctx *pulumi.Context, return nil, fmt.Errorf("error creating scale set: %v", err) } + component.PrivateKey = key.PrivateKeyOpenssh + component.ScaleSetName = scaleset.Name + if err := ctx.RegisterResourceOutputs(component, pulumi.Map{ "scaleSetName": scaleset.Name, "privateKey": key.PrivateKeyOpenssh, diff --git a/provider/pkg/provider/azure/userdata.tmpl b/provider/pkg/provider/azure/userdata.tmpl index 6e8ea3c..4fd527e 100644 --- a/provider/pkg/provider/azure/userdata.tmpl +++ b/provider/pkg/provider/azure/userdata.tmpl @@ -11,6 +11,6 @@ AZ_REPO=$(lsb_release -cs) echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | sudo tee /etc/apt/sources.list.d/azure-cli.list sudo apt-get update -sudo apt-get install azure-cli tailscale +sudo apt-get install -y azure-cli tailscale -sudo tailscale up --advertise-connector="{{ .EnableAppConnector }}" --advertise-exit-node="{{ .EnableExitNode }}" --hostname="{{ .Hostname}}" --ssh="{{ .EnableSSH }}" --advertise-tags="{{ .TailscaleTags}}" {{if .Routes}}--advertise-routes="{{ .Routes }}"{{end}} --authkey=$(aws ssm get-parameter --name {{.ParameterName}} --region {{.Region}} --with-decryption | jq .Parameter.Value -r) --host-routes \ No newline at end of file +sudo tailscale up --advertise-connector="{{ .EnableAppConnector }}" --advertise-exit-node="{{ .EnableExitNode }}" --hostname="{{ .Hostname}}" --ssh="{{ .EnableSSH }}" --advertise-tags="{{ .TailscaleTags}}" {{if .Routes}}--advertise-routes="{{ .Routes }}"{{end}} --authkey="{{ .AuthKey }}" --host-routes --accept-dns=false \ No newline at end of file diff --git a/schema.yaml b/schema.yaml index 02a59bd..11e72d8 100644 --- a/schema.yaml +++ b/schema.yaml @@ -39,6 +39,10 @@ resources: type: boolean description: "Whether the bastion should be highly available." default: false + public: + type: boolean + description: "Whether the bastion should have a public IP." + default: false tailscaleTags: type: array items: diff --git a/sdk/dotnet/TailscaleBastion/Azure/Bastion.cs b/sdk/dotnet/TailscaleBastion/Azure/Bastion.cs index 00dc34d..f64ed7d 100644 --- a/sdk/dotnet/TailscaleBastion/Azure/Bastion.cs +++ b/sdk/dotnet/TailscaleBastion/Azure/Bastion.cs @@ -78,6 +78,12 @@ public sealed class BastionArgs : global::Pulumi.ResourceArgs [Input("location", required: true)] public Input Location { get; set; } = null!; + /// + /// Whether the bastion should have a public IP. + /// + [Input("public")] + public Input? Public { get; set; } + /// /// The Azure resource group to create the bastion in. /// @@ -112,6 +118,7 @@ public BastionArgs() { EnableSSH = true; HighAvailability = false; + Public = false; } public static new BastionArgs Empty => new BastionArgs(); } diff --git a/sdk/go/bastion/azure/bastion.go b/sdk/go/bastion/azure/bastion.go index b5a9b56..b50ef79 100644 --- a/sdk/go/bastion/azure/bastion.go +++ b/sdk/go/bastion/azure/bastion.go @@ -50,6 +50,9 @@ func NewBastion(ctx *pulumi.Context, if args.HighAvailability == nil { args.HighAvailability = pulumi.Bool(false) } + if args.Public == nil { + args.Public = pulumi.BoolPtr(false) + } opts = internal.PkgResourceDefaultOpts(opts) var resource Bastion err := ctx.RegisterRemoteComponentResource("tailscale-bastion:azure:Bastion", name, args, &resource, opts...) @@ -68,6 +71,8 @@ type bastionArgs struct { InstanceSku *string `pulumi:"instanceSku"` // The Azure region you're using. Location string `pulumi:"location"` + // Whether the bastion should have a public IP. + Public *bool `pulumi:"public"` // The Azure resource group to create the bastion in. ResourceGroupName string `pulumi:"resourceGroupName"` // The route you'd like to advertise via tailscale. @@ -88,6 +93,8 @@ type BastionArgs struct { InstanceSku pulumi.StringPtrInput // The Azure region you're using. Location pulumi.StringInput + // Whether the bastion should have a public IP. + Public pulumi.BoolPtrInput // The Azure resource group to create the bastion in. ResourceGroupName pulumi.StringInput // The route you'd like to advertise via tailscale. diff --git a/sdk/nodejs/azure/bastion.ts b/sdk/nodejs/azure/bastion.ts index 58609db..c9ec9bf 100644 --- a/sdk/nodejs/azure/bastion.ts +++ b/sdk/nodejs/azure/bastion.ts @@ -61,6 +61,7 @@ export class Bastion extends pulumi.ComponentResource { resourceInputs["highAvailability"] = (args ? args.highAvailability : undefined) ?? false; resourceInputs["instanceSku"] = args ? args.instanceSku : undefined; resourceInputs["location"] = args ? args.location : undefined; + resourceInputs["public"] = (args ? args.public : undefined) ?? false; resourceInputs["resourceGroupName"] = args ? args.resourceGroupName : undefined; resourceInputs["route"] = args ? args.route : undefined; resourceInputs["subnetId"] = args ? args.subnetId : undefined; @@ -96,6 +97,10 @@ export interface BastionArgs { * The Azure region you're using. */ location: pulumi.Input; + /** + * Whether the bastion should have a public IP. + */ + public?: pulumi.Input; /** * The Azure resource group to create the bastion in. */ diff --git a/sdk/python/lbrlabs_pulumi_tailscalebastion/azure/bastion.py b/sdk/python/lbrlabs_pulumi_tailscalebastion/azure/bastion.py index 23fac74..6e7e782 100644 --- a/sdk/python/lbrlabs_pulumi_tailscalebastion/azure/bastion.py +++ b/sdk/python/lbrlabs_pulumi_tailscalebastion/azure/bastion.py @@ -21,7 +21,8 @@ def __init__(__self__, *, subnet_id: pulumi.Input[str], tailscale_tags: pulumi.Input[Sequence[pulumi.Input[str]]], enable_ssh: Optional[pulumi.Input[bool]] = None, - instance_sku: Optional[pulumi.Input[str]] = None): + instance_sku: Optional[pulumi.Input[str]] = None, + public: Optional[pulumi.Input[bool]] = None): """ The set of arguments for constructing a Bastion resource. :param pulumi.Input[bool] high_availability: Whether the bastion should be highly available. @@ -32,6 +33,7 @@ def __init__(__self__, *, :param pulumi.Input[Sequence[pulumi.Input[str]]] tailscale_tags: The tags to apply to the tailnet device andauth key. This tag should be added to your oauth key and ACL. :param pulumi.Input[bool] enable_ssh: Whether to enable SSH access to the bastion. :param pulumi.Input[str] instance_sku: The Azure instance SKU to use for the bastion. + :param pulumi.Input[bool] public: Whether the bastion should have a public IP. """ if high_availability is None: high_availability = False @@ -47,6 +49,10 @@ def __init__(__self__, *, pulumi.set(__self__, "enable_ssh", enable_ssh) if instance_sku is not None: pulumi.set(__self__, "instance_sku", instance_sku) + if public is None: + public = False + if public is not None: + pulumi.set(__self__, "public", public) @property @pulumi.getter(name="highAvailability") @@ -144,6 +150,18 @@ def instance_sku(self) -> Optional[pulumi.Input[str]]: def instance_sku(self, value: Optional[pulumi.Input[str]]): pulumi.set(self, "instance_sku", value) + @property + @pulumi.getter + def public(self) -> Optional[pulumi.Input[bool]]: + """ + Whether the bastion should have a public IP. + """ + return pulumi.get(self, "public") + + @public.setter + def public(self, value: Optional[pulumi.Input[bool]]): + pulumi.set(self, "public", value) + class Bastion(pulumi.ComponentResource): @overload @@ -154,6 +172,7 @@ def __init__(__self__, high_availability: Optional[pulumi.Input[bool]] = None, instance_sku: Optional[pulumi.Input[str]] = None, location: Optional[pulumi.Input[str]] = None, + public: Optional[pulumi.Input[bool]] = None, resource_group_name: Optional[pulumi.Input[str]] = None, route: Optional[pulumi.Input[str]] = None, subnet_id: Optional[pulumi.Input[str]] = None, @@ -167,6 +186,7 @@ def __init__(__self__, :param pulumi.Input[bool] high_availability: Whether the bastion should be highly available. :param pulumi.Input[str] instance_sku: The Azure instance SKU to use for the bastion. :param pulumi.Input[str] location: The Azure region you're using. + :param pulumi.Input[bool] public: Whether the bastion should have a public IP. :param pulumi.Input[str] resource_group_name: The Azure resource group to create the bastion in. :param pulumi.Input[str] route: The route you'd like to advertise via tailscale. :param pulumi.Input[str] subnet_id: The subnet Ids to launch instances in. @@ -199,6 +219,7 @@ def _internal_init(__self__, high_availability: Optional[pulumi.Input[bool]] = None, instance_sku: Optional[pulumi.Input[str]] = None, location: Optional[pulumi.Input[str]] = None, + public: Optional[pulumi.Input[bool]] = None, resource_group_name: Optional[pulumi.Input[str]] = None, route: Optional[pulumi.Input[str]] = None, subnet_id: Optional[pulumi.Input[str]] = None, @@ -226,6 +247,9 @@ def _internal_init(__self__, if location is None and not opts.urn: raise TypeError("Missing required property 'location'") __props__.__dict__["location"] = location + if public is None: + public = False + __props__.__dict__["public"] = public if resource_group_name is None and not opts.urn: raise TypeError("Missing required property 'resource_group_name'") __props__.__dict__["resource_group_name"] = resource_group_name