diff --git a/provider/pkg/provider/aws/bastion.go b/provider/pkg/provider/aws/bastion.go index d327d55..142602d 100644 --- a/provider/pkg/provider/aws/bastion.go +++ b/provider/pkg/provider/aws/bastion.go @@ -6,9 +6,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "strings" - "text/template" - "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/autoscaling" "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2" "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/iam" @@ -16,6 +13,8 @@ import ( "github.com/pulumi/pulumi-tailscale/sdk/go/tailscale" tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "strings" + "text/template" ) var ( @@ -28,7 +27,7 @@ type BastionArgs struct { VpcID pulumi.StringInput `pulumi:"vpcId"` SubnetIds pulumi.StringArrayInput `pulumi:"subnetIds"` TailscaleTags pulumi.StringArrayInput `pulumi:"tailscaleTags"` - Route pulumi.StringInput `pulumi:"route"` + Routes pulumi.StringArrayInput `pulumi:"routes"` Region pulumi.StringInput `pulumi:"region"` InstanceType pulumi.StringInput `pulumi:"instanceType"` Hostname pulumi.StringInput `pulumi:"hostname"` @@ -41,7 +40,7 @@ type BastionArgs struct { type UserDataArgs struct { ParameterName string - Route string + Routes string Region string TailscaleTags string EnableSSH bool @@ -50,7 +49,6 @@ type UserDataArgs struct { Hostname string } - // The Bastion component resource. type Bastion struct { pulumi.ResourceState @@ -275,14 +273,23 @@ func NewBastion(ctx *pulumi.Context, MostRecent: pulumi.BoolPtr(true), }, pulumi.Parent(component)) - data := pulumi.All(tailnetKeySsmParameter.Name, args.Route, args.Region, args.TailscaleTags, args.EnableSSH, hostname, args.EnableExitNode, args.EnableAppConnector).ApplyT( + data := pulumi.All(tailnetKeySsmParameter.Name, args.Routes, args.Region, 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[3].([]string), ",") + + var routesCsv string + + if args[1] != nil { + routes := args[1].([]string) + routesCsv = strings.Join(routes, ",") + } else { + routesCsv = "" + } d := UserDataArgs{ ParameterName: args[0].(string), - Route: args[1].(string), + Routes: routesCsv, Region: args[2].(string), TailscaleTags: tagCSV, EnableSSH: args[4].(bool), diff --git a/provider/pkg/provider/aws/userdata.tmpl b/provider/pkg/provider/aws/userdata.tmpl index 646ccae..f1e183d 100644 --- a/provider/pkg/provider/aws/userdata.tmpl +++ b/provider/pkg/provider/aws/userdata.tmpl @@ -18,4 +18,4 @@ sudo yum-config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linu sudo yum install tailscale -y sudo systemctl enable --now tailscaled sleep 10 -sudo tailscale up --advertise-connector="{{ .EnableAppConnector }}" --advertise-exit-node="{{ .EnableExitNode }}" --hostname="{{ .Hostname}}" --ssh="{{ .EnableSSH }}" --advertise-tags="{{ .TailscaleTags}}" --advertise-routes="{{ .Route }}" --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=$(aws ssm get-parameter --name {{.ParameterName}} --region {{.Region}} --with-decryption | jq .Parameter.Value -r) --host-routes \ No newline at end of file diff --git a/provider/pkg/provider/azure/bastion.go b/provider/pkg/provider/azure/bastion.go index ca5668e..ae4f9ac 100644 --- a/provider/pkg/provider/azure/bastion.go +++ b/provider/pkg/provider/azure/bastion.go @@ -21,26 +21,27 @@ var ( // The set of arguments for creating a Bastion component resource. type BastionArgs struct { - ResourceGroupName pulumi.StringInput `pulumi:"resourceGroupName"` - SubnetID pulumi.StringInput `pulumi:"subnetId"` - Location pulumi.StringInput `pulumi:"location"` - Route pulumi.StringInput `pulumi:"route"` - InstanceSku pulumi.StringInput `pulumi:"instanceSku"` - TailscaleTags pulumi.StringArrayInput `pulumi:"tailscaleTags"` - HighAvailability bool `pulumi:"highAvailability"` - EnableSSH bool `pulumi:"enableSSH"` + ResourceGroupName pulumi.StringInput `pulumi:"resourceGroupName"` + SubnetID pulumi.StringInput `pulumi:"subnetId"` + Location pulumi.StringInput `pulumi:"location"` + Routes pulumi.StringArrayInput `pulumi:"routes"` + InstanceSku pulumi.StringInput `pulumi:"instanceSku"` + TailscaleTags pulumi.StringArrayInput `pulumi:"tailscaleTags"` + Hostname pulumi.StringInput `pulumi:"hostname"` + HighAvailability bool `pulumi:"highAvailability"` + EnableSSH bool `pulumi:"enableSSH"` + EnableExitNode bool `pulumi:"enableExitNode"` + EnableAppConnector bool `pulumi:"enableAppConnector"` } type UserDataArgs struct { - AuthKey string - Route string - TailscaleTags []string - EnableSSH bool -} - -// Join the tags into a CSV -func (uda *UserDataArgs) JoinedTags() string { - return strings.Join(uda.TailscaleTags, ",") + AuthKey string + Routes string + TailscaleTags string + EnableSSH bool + EnableExitNode bool + EnableAppConnector bool + Hostname string } // The Bastion component resource. @@ -65,6 +66,14 @@ func NewBastion(ctx *pulumi.Context, return nil, err } + var hostname pulumi.StringInput + + if args.Hostname == nil { + hostname = pulumi.String(name) + } else { + hostname = args.Hostname + } + // create a tailnet key to auth devices tailnetKey, err := tailscale.NewTailnetKey(ctx, name, &tailscale.TailnetKeyArgs{ Ephemeral: pulumi.Bool(true), @@ -76,13 +85,28 @@ func NewBastion(ctx *pulumi.Context, return nil, fmt.Errorf("error creating tailnet key: %v", err) } - data := pulumi.All(tailnetKey.Key, args.Route, args.TailscaleTags, args.EnableSSH).ApplyT( + 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), ",") + + var routesCsv string + + if args[1] != nil { + routes := args[1].([]string) + routesCsv = strings.Join(routes, ",") + } else { + routesCsv = "" + } + d := UserDataArgs{ - AuthKey: args[0].(string), - Route: args[1].(string), - TailscaleTags: args[2].([]string), - EnableSSH: args[3].(bool), + AuthKey: args[0].(string), + Routes: routesCsv, + TailscaleTags: tagCSV, + EnableSSH: args[3].(bool), + Hostname: args[4].(string), + EnableExitNode: args[5].(bool), + EnableAppConnector: args[6].(bool), } var userDataBytes bytes.Buffer diff --git a/provider/pkg/provider/azure/userdata.tmpl b/provider/pkg/provider/azure/userdata.tmpl index ac5685e..6e8ea3c 100644 --- a/provider/pkg/provider/azure/userdata.tmpl +++ b/provider/pkg/provider/azure/userdata.tmpl @@ -13,4 +13,4 @@ echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO sudo apt-get update sudo apt-get install azure-cli tailscale -sudo tailscale up --ssh="{{ .EnableSSH }}" --advertise-tags="{{ .JoinedTags }}" --advertise-routes="{{ .Route }}" --authkey="{{ .AuthKey }}" --host-routes --accept-dns=false \ 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=$(aws ssm get-parameter --name {{.ParameterName}} --region {{.Region}} --with-decryption | jq .Parameter.Value -r) --host-routes \ No newline at end of file diff --git a/schema.yaml b/schema.yaml index ba7faea..02a59bd 100644 --- a/schema.yaml +++ b/schema.yaml @@ -100,9 +100,11 @@ resources: items: type: string description: "The subnet Ids to launch instances in." - route: - type: string - description: "The route you'd like to advertise via tailscale." + routes: + type: array + items: + type: string + description: "The routes you'd like to advertise via tailscale." region: type: string description: "The AWS region you're using." @@ -113,7 +115,6 @@ resources: - highAvailability - vpcId - subnetIds - - route - region - tailscaleTags properties: diff --git a/sdk/dotnet/TailscaleBastion/Aws/Bastion.cs b/sdk/dotnet/TailscaleBastion/Aws/Bastion.cs index 981d947..096827b 100644 --- a/sdk/dotnet/TailscaleBastion/Aws/Bastion.cs +++ b/sdk/dotnet/TailscaleBastion/Aws/Bastion.cs @@ -102,11 +102,17 @@ public sealed class BastionArgs : global::Pulumi.ResourceArgs [Input("region", required: true)] public Input Region { get; set; } = null!; + [Input("routes")] + private InputList? _routes; + /// - /// The route you'd like to advertise via tailscale. + /// The routes you'd like to advertise via tailscale. /// - [Input("route", required: true)] - public Input Route { get; set; } = null!; + public InputList Routes + { + get => _routes ?? (_routes = new InputList()); + set => _routes = value; + } [Input("subnetIds", required: true)] private InputList? _subnetIds; diff --git a/sdk/go/bastion/aws/bastion.go b/sdk/go/bastion/aws/bastion.go index c06ba2f..27379b8 100644 --- a/sdk/go/bastion/aws/bastion.go +++ b/sdk/go/bastion/aws/bastion.go @@ -32,9 +32,6 @@ func NewBastion(ctx *pulumi.Context, if args.Region == nil { return nil, errors.New("invalid value for required argument 'Region'") } - if args.Route == nil { - return nil, errors.New("invalid value for required argument 'Route'") - } if args.SubnetIds == nil { return nil, errors.New("invalid value for required argument 'SubnetIds'") } @@ -85,8 +82,8 @@ type bastionArgs struct { Public *bool `pulumi:"public"` // The AWS region you're using. Region string `pulumi:"region"` - // The route you'd like to advertise via tailscale. - Route string `pulumi:"route"` + // The routes you'd like to advertise via tailscale. + Routes []string `pulumi:"routes"` // The subnet Ids to launch instances in. SubnetIds []string `pulumi:"subnetIds"` // The tags to apply to the tailnet device andauth key. This tag should be added to your oauth key and ACL. @@ -113,8 +110,8 @@ type BastionArgs struct { Public pulumi.BoolPtrInput // The AWS region you're using. Region pulumi.StringInput - // The route you'd like to advertise via tailscale. - Route pulumi.StringInput + // The routes you'd like to advertise via tailscale. + Routes pulumi.StringArrayInput // The subnet Ids to launch instances in. SubnetIds pulumi.StringArrayInput // The tags to apply to the tailnet device andauth key. This tag should be added to your oauth key and ACL. diff --git a/sdk/nodejs/aws/bastion.ts b/sdk/nodejs/aws/bastion.ts index cd82b7a..62a3575 100644 --- a/sdk/nodejs/aws/bastion.ts +++ b/sdk/nodejs/aws/bastion.ts @@ -45,9 +45,6 @@ export class Bastion extends pulumi.ComponentResource { if ((!args || args.region === undefined) && !opts.urn) { throw new Error("Missing required property 'region'"); } - if ((!args || args.route === undefined) && !opts.urn) { - throw new Error("Missing required property 'route'"); - } if ((!args || args.subnetIds === undefined) && !opts.urn) { throw new Error("Missing required property 'subnetIds'"); } @@ -65,7 +62,7 @@ export class Bastion extends pulumi.ComponentResource { resourceInputs["instanceType"] = args ? args.instanceType : undefined; resourceInputs["public"] = (args ? args.public : undefined) ?? false; resourceInputs["region"] = args ? args.region : undefined; - resourceInputs["route"] = args ? args.route : undefined; + resourceInputs["routes"] = args ? args.routes : undefined; resourceInputs["subnetIds"] = args ? args.subnetIds : undefined; resourceInputs["tailscaleTags"] = args ? args.tailscaleTags : undefined; resourceInputs["vpcId"] = args ? args.vpcId : undefined; @@ -117,9 +114,9 @@ export interface BastionArgs { */ region: pulumi.Input; /** - * The route you'd like to advertise via tailscale. + * The routes you'd like to advertise via tailscale. */ - route: pulumi.Input; + routes?: pulumi.Input[]>; /** * The subnet Ids to launch instances in. */ diff --git a/sdk/python/lbrlabs_pulumi_tailscalebastion/aws/bastion.py b/sdk/python/lbrlabs_pulumi_tailscalebastion/aws/bastion.py index b145534..c17840c 100644 --- a/sdk/python/lbrlabs_pulumi_tailscalebastion/aws/bastion.py +++ b/sdk/python/lbrlabs_pulumi_tailscalebastion/aws/bastion.py @@ -16,7 +16,6 @@ class BastionArgs: def __init__(__self__, *, high_availability: Optional[pulumi.Input[bool]] = None, region: pulumi.Input[str], - route: pulumi.Input[str], subnet_ids: pulumi.Input[Sequence[pulumi.Input[str]]], tailscale_tags: pulumi.Input[Sequence[pulumi.Input[str]]], vpc_id: pulumi.Input[str], @@ -25,12 +24,12 @@ def __init__(__self__, *, enable_ssh: Optional[pulumi.Input[bool]] = None, hostname: Optional[pulumi.Input[str]] = None, instance_type: Optional[pulumi.Input[str]] = None, - public: Optional[pulumi.Input[bool]] = None): + public: Optional[pulumi.Input[bool]] = None, + routes: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None): """ The set of arguments for constructing a Bastion resource. :param pulumi.Input[bool] high_availability: Whether the bastion should be highly available. :param pulumi.Input[str] region: The AWS region you're using. - :param pulumi.Input[str] route: The route you'd like to advertise via tailscale. :param pulumi.Input[Sequence[pulumi.Input[str]]] subnet_ids: The subnet Ids to launch instances in. :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[str] vpc_id: The VPC the Bastion should be created in. @@ -40,12 +39,12 @@ def __init__(__self__, *, :param pulumi.Input[str] hostname: The hostname of the bastion. :param pulumi.Input[str] instance_type: The EC2 instance type to use for the bastion. :param pulumi.Input[bool] public: Whether the bastion is going in public subnets. + :param pulumi.Input[Sequence[pulumi.Input[str]]] routes: The routes you'd like to advertise via tailscale. """ if high_availability is None: high_availability = False pulumi.set(__self__, "high_availability", high_availability) pulumi.set(__self__, "region", region) - pulumi.set(__self__, "route", route) pulumi.set(__self__, "subnet_ids", subnet_ids) pulumi.set(__self__, "tailscale_tags", tailscale_tags) pulumi.set(__self__, "vpc_id", vpc_id) @@ -69,6 +68,8 @@ def __init__(__self__, *, public = False if public is not None: pulumi.set(__self__, "public", public) + if routes is not None: + pulumi.set(__self__, "routes", routes) @property @pulumi.getter(name="highAvailability") @@ -94,18 +95,6 @@ def region(self) -> pulumi.Input[str]: def region(self, value: pulumi.Input[str]): pulumi.set(self, "region", value) - @property - @pulumi.getter - def route(self) -> pulumi.Input[str]: - """ - The route you'd like to advertise via tailscale. - """ - return pulumi.get(self, "route") - - @route.setter - def route(self, value: pulumi.Input[str]): - pulumi.set(self, "route", value) - @property @pulumi.getter(name="subnetIds") def subnet_ids(self) -> pulumi.Input[Sequence[pulumi.Input[str]]]: @@ -214,6 +203,18 @@ def public(self) -> Optional[pulumi.Input[bool]]: def public(self, value: Optional[pulumi.Input[bool]]): pulumi.set(self, "public", value) + @property + @pulumi.getter + def routes(self) -> Optional[pulumi.Input[Sequence[pulumi.Input[str]]]]: + """ + The routes you'd like to advertise via tailscale. + """ + return pulumi.get(self, "routes") + + @routes.setter + def routes(self, value: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]]): + pulumi.set(self, "routes", value) + class Bastion(pulumi.ComponentResource): @overload @@ -228,7 +229,7 @@ def __init__(__self__, instance_type: Optional[pulumi.Input[str]] = None, public: Optional[pulumi.Input[bool]] = None, region: Optional[pulumi.Input[str]] = None, - route: Optional[pulumi.Input[str]] = None, + routes: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, subnet_ids: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, tailscale_tags: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, vpc_id: Optional[pulumi.Input[str]] = None, @@ -245,7 +246,7 @@ def __init__(__self__, :param pulumi.Input[str] instance_type: The EC2 instance type to use for the bastion. :param pulumi.Input[bool] public: Whether the bastion is going in public subnets. :param pulumi.Input[str] region: The AWS region you're using. - :param pulumi.Input[str] route: The route you'd like to advertise via tailscale. + :param pulumi.Input[Sequence[pulumi.Input[str]]] routes: The routes you'd like to advertise via tailscale. :param pulumi.Input[Sequence[pulumi.Input[str]]] subnet_ids: The subnet Ids to launch instances in. :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[str] vpc_id: The VPC the Bastion should be created in. @@ -281,7 +282,7 @@ def _internal_init(__self__, instance_type: Optional[pulumi.Input[str]] = None, public: Optional[pulumi.Input[bool]] = None, region: Optional[pulumi.Input[str]] = None, - route: Optional[pulumi.Input[str]] = None, + routes: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, subnet_ids: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, tailscale_tags: Optional[pulumi.Input[Sequence[pulumi.Input[str]]]] = None, vpc_id: Optional[pulumi.Input[str]] = None, @@ -318,9 +319,7 @@ def _internal_init(__self__, if region is None and not opts.urn: raise TypeError("Missing required property 'region'") __props__.__dict__["region"] = region - if route is None and not opts.urn: - raise TypeError("Missing required property 'route'") - __props__.__dict__["route"] = route + __props__.__dict__["routes"] = routes if subnet_ids is None and not opts.urn: raise TypeError("Missing required property 'subnet_ids'") __props__.__dict__["subnet_ids"] = subnet_ids