github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/provisioning_test.go (about)

     1  /*
     2  Copyright 2022 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/gravitational/trace"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/gravitational/teleport/api/defaults"
    27  	"github.com/gravitational/teleport/api/fixtures"
    28  )
    29  
    30  func TestProvisionTokenV2_CheckAndSetDefaults(t *testing.T) {
    31  	testcases := []struct {
    32  		desc     string
    33  		token    *ProvisionTokenV2
    34  		expected *ProvisionTokenV2
    35  		wantErr  bool
    36  	}{
    37  		{
    38  			desc:    "empty",
    39  			token:   &ProvisionTokenV2{},
    40  			wantErr: true,
    41  		},
    42  		{
    43  			desc: "missing roles",
    44  			token: &ProvisionTokenV2{
    45  				Metadata: Metadata{
    46  					Name: "test",
    47  				},
    48  			},
    49  			wantErr: true,
    50  		},
    51  		{
    52  			desc: "invalid role",
    53  			token: &ProvisionTokenV2{
    54  				Metadata: Metadata{
    55  					Name: "test",
    56  				},
    57  				Spec: ProvisionTokenSpecV2{
    58  					Roles: []SystemRole{RoleNode, "not a role"},
    59  				},
    60  			},
    61  			wantErr: true,
    62  		},
    63  		{
    64  			desc: "simple token",
    65  			token: &ProvisionTokenV2{
    66  				Metadata: Metadata{
    67  					Name: "test",
    68  				},
    69  				Spec: ProvisionTokenSpecV2{
    70  					Roles: []SystemRole{RoleNode},
    71  				},
    72  			},
    73  			expected: &ProvisionTokenV2{
    74  				Kind:    "token",
    75  				Version: "v2",
    76  				Metadata: Metadata{
    77  					Name:      "test",
    78  					Namespace: "default",
    79  				},
    80  				Spec: ProvisionTokenSpecV2{
    81  					Roles:      []SystemRole{RoleNode},
    82  					JoinMethod: "token",
    83  				},
    84  			},
    85  		},
    86  		{
    87  			desc: "implicit ec2 method",
    88  			token: &ProvisionTokenV2{
    89  				Metadata: Metadata{
    90  					Name: "test",
    91  				},
    92  				Spec: ProvisionTokenSpecV2{
    93  					Roles: []SystemRole{RoleNode},
    94  					Allow: []*TokenRule{
    95  						{
    96  							AWSAccount: "1234",
    97  							AWSRole:    "1234/role",
    98  							AWSRegions: []string{"us-west-2"},
    99  						},
   100  					},
   101  				},
   102  			},
   103  			expected: &ProvisionTokenV2{
   104  				Kind:    "token",
   105  				Version: "v2",
   106  				Metadata: Metadata{
   107  					Name:      "test",
   108  					Namespace: "default",
   109  				},
   110  				Spec: ProvisionTokenSpecV2{
   111  					Roles:      []SystemRole{RoleNode},
   112  					JoinMethod: "ec2",
   113  					Allow: []*TokenRule{
   114  						{
   115  							AWSAccount: "1234",
   116  							AWSRole:    "1234/role",
   117  							AWSRegions: []string{"us-west-2"},
   118  						},
   119  					},
   120  					AWSIIDTTL: Duration(5 * time.Minute),
   121  				},
   122  			},
   123  		},
   124  		{
   125  			desc: "explicit ec2 method",
   126  			token: &ProvisionTokenV2{
   127  				Metadata: Metadata{
   128  					Name: "test",
   129  				},
   130  				Spec: ProvisionTokenSpecV2{
   131  					Roles:      []SystemRole{RoleNode},
   132  					JoinMethod: "ec2",
   133  					Allow:      []*TokenRule{{AWSAccount: "1234"}},
   134  				},
   135  			},
   136  			expected: &ProvisionTokenV2{
   137  				Kind:    "token",
   138  				Version: "v2",
   139  				Metadata: Metadata{
   140  					Name:      "test",
   141  					Namespace: "default",
   142  				},
   143  				Spec: ProvisionTokenSpecV2{
   144  					Roles:      []SystemRole{RoleNode},
   145  					JoinMethod: "ec2",
   146  					Allow:      []*TokenRule{{AWSAccount: "1234"}},
   147  					AWSIIDTTL:  Duration(5 * time.Minute),
   148  				},
   149  			},
   150  		},
   151  		{
   152  			desc: "ec2 method no allow rules",
   153  			token: &ProvisionTokenV2{
   154  				Metadata: Metadata{
   155  					Name: "test",
   156  				},
   157  				Spec: ProvisionTokenSpecV2{
   158  					Roles:      []SystemRole{RoleNode},
   159  					JoinMethod: "ec2",
   160  				},
   161  			},
   162  			wantErr: true,
   163  		},
   164  		{
   165  			desc: "ec2 method with aws_arn",
   166  			token: &ProvisionTokenV2{
   167  				Metadata: Metadata{
   168  					Name: "test",
   169  				},
   170  				Spec: ProvisionTokenSpecV2{
   171  					Roles:      []SystemRole{RoleNode},
   172  					JoinMethod: "ec2",
   173  					Allow: []*TokenRule{
   174  						{
   175  							AWSAccount: "1234",
   176  							AWSARN:     "1234",
   177  						},
   178  					},
   179  				},
   180  			},
   181  			wantErr: true,
   182  		},
   183  		{
   184  			desc: "ec2 method empty rule",
   185  			token: &ProvisionTokenV2{
   186  				Metadata: Metadata{
   187  					Name: "test",
   188  				},
   189  				Spec: ProvisionTokenSpecV2{
   190  					Roles:      []SystemRole{RoleNode},
   191  					JoinMethod: "ec2",
   192  					Allow:      []*TokenRule{{}},
   193  				},
   194  			},
   195  			wantErr: true,
   196  		},
   197  		{
   198  			desc: "iam method",
   199  			token: &ProvisionTokenV2{
   200  				Metadata: Metadata{
   201  					Name: "test",
   202  				},
   203  				Spec: ProvisionTokenSpecV2{
   204  					Roles:      []SystemRole{RoleNode},
   205  					JoinMethod: "ec2",
   206  					Allow:      []*TokenRule{{AWSAccount: "1234"}},
   207  				},
   208  			},
   209  			expected: &ProvisionTokenV2{
   210  				Kind:    "token",
   211  				Version: "v2",
   212  				Metadata: Metadata{
   213  					Name:      "test",
   214  					Namespace: "default",
   215  				},
   216  				Spec: ProvisionTokenSpecV2{
   217  					Roles:      []SystemRole{RoleNode},
   218  					JoinMethod: "ec2",
   219  					Allow:      []*TokenRule{{AWSAccount: "1234"}},
   220  					AWSIIDTTL:  Duration(5 * time.Minute),
   221  				},
   222  			},
   223  		},
   224  		{
   225  			desc: "iam method with aws_role",
   226  			token: &ProvisionTokenV2{
   227  				Metadata: Metadata{
   228  					Name: "test",
   229  				},
   230  				Spec: ProvisionTokenSpecV2{
   231  					Roles:      []SystemRole{RoleNode},
   232  					JoinMethod: "iam",
   233  					Allow: []*TokenRule{
   234  						{
   235  							AWSAccount: "1234",
   236  							AWSRole:    "1234/role",
   237  						},
   238  					},
   239  				},
   240  			},
   241  			wantErr: true,
   242  		},
   243  		{
   244  			desc: "iam method with aws_regions",
   245  			token: &ProvisionTokenV2{
   246  				Metadata: Metadata{
   247  					Name: "test",
   248  				},
   249  				Spec: ProvisionTokenSpecV2{
   250  					Roles:      []SystemRole{RoleNode},
   251  					JoinMethod: "iam",
   252  					Allow: []*TokenRule{
   253  						{
   254  							AWSAccount: "1234",
   255  							AWSRegions: []string{"us-west-2"},
   256  						},
   257  					},
   258  				},
   259  			},
   260  			wantErr: true,
   261  		},
   262  		{
   263  			desc: "github valid",
   264  			token: &ProvisionTokenV2{
   265  				Metadata: Metadata{
   266  					Name: "test",
   267  				},
   268  				Spec: ProvisionTokenSpecV2{
   269  					Roles:      []SystemRole{RoleNode},
   270  					JoinMethod: JoinMethodGitHub,
   271  					GitHub: &ProvisionTokenSpecV2GitHub{
   272  						Allow: []*ProvisionTokenSpecV2GitHub_Rule{
   273  							{
   274  								Sub: "foo",
   275  							},
   276  						},
   277  					},
   278  				},
   279  			},
   280  		},
   281  		{
   282  			desc: "github ghes valid",
   283  			token: &ProvisionTokenV2{
   284  				Metadata: Metadata{
   285  					Name: "test",
   286  				},
   287  				Spec: ProvisionTokenSpecV2{
   288  					Roles:      []SystemRole{RoleNode},
   289  					JoinMethod: JoinMethodGitHub,
   290  					GitHub: &ProvisionTokenSpecV2GitHub{
   291  						EnterpriseServerHost: "example.com",
   292  						Allow: []*ProvisionTokenSpecV2GitHub_Rule{
   293  							{
   294  								Sub: "foo",
   295  							},
   296  						},
   297  					},
   298  				},
   299  			},
   300  		},
   301  		{
   302  			desc: "github ghes invalid",
   303  			token: &ProvisionTokenV2{
   304  				Metadata: Metadata{
   305  					Name: "test",
   306  				},
   307  				Spec: ProvisionTokenSpecV2{
   308  					Roles:      []SystemRole{RoleNode},
   309  					JoinMethod: JoinMethodGitHub,
   310  					GitHub: &ProvisionTokenSpecV2GitHub{
   311  						EnterpriseServerHost: "https://example.com",
   312  						Allow: []*ProvisionTokenSpecV2GitHub_Rule{
   313  							{
   314  								Sub: "foo",
   315  							},
   316  						},
   317  					},
   318  				},
   319  			},
   320  			wantErr: true,
   321  		},
   322  		{
   323  			desc: "github slug and ghes set",
   324  			token: &ProvisionTokenV2{
   325  				Metadata: Metadata{
   326  					Name: "test",
   327  				},
   328  				Spec: ProvisionTokenSpecV2{
   329  					Roles:      []SystemRole{RoleNode},
   330  					JoinMethod: JoinMethodGitHub,
   331  					GitHub: &ProvisionTokenSpecV2GitHub{
   332  						EnterpriseServerHost: "example.com",
   333  						EnterpriseSlug:       "slug",
   334  						Allow: []*ProvisionTokenSpecV2GitHub_Rule{
   335  							{
   336  								Sub: "foo",
   337  							},
   338  						},
   339  					},
   340  				},
   341  			},
   342  			wantErr: true,
   343  		},
   344  		{
   345  			desc: "circleci valid",
   346  			token: &ProvisionTokenV2{
   347  				Metadata: Metadata{
   348  					Name: "test",
   349  				},
   350  				Spec: ProvisionTokenSpecV2{
   351  					Roles:      []SystemRole{RoleNode},
   352  					JoinMethod: JoinMethodCircleCI,
   353  					CircleCI: &ProvisionTokenSpecV2CircleCI{
   354  						OrganizationID: "foo",
   355  						Allow: []*ProvisionTokenSpecV2CircleCI_Rule{
   356  							{
   357  								ProjectID: "foo",
   358  								ContextID: "bar",
   359  							},
   360  						},
   361  					},
   362  				},
   363  			},
   364  		},
   365  		{
   366  			desc: "circleci and no allow",
   367  			token: &ProvisionTokenV2{
   368  				Metadata: Metadata{
   369  					Name: "test",
   370  				},
   371  				Spec: ProvisionTokenSpecV2{
   372  					Roles:      []SystemRole{RoleNode},
   373  					JoinMethod: JoinMethodCircleCI,
   374  					CircleCI: &ProvisionTokenSpecV2CircleCI{
   375  						OrganizationID: "foo",
   376  					},
   377  				},
   378  			},
   379  			wantErr: true,
   380  		},
   381  		{
   382  			desc: "circleci and no org id",
   383  			token: &ProvisionTokenV2{
   384  				Metadata: Metadata{
   385  					Name: "test",
   386  				},
   387  				Spec: ProvisionTokenSpecV2{
   388  					Roles:      []SystemRole{RoleNode},
   389  					JoinMethod: JoinMethodCircleCI,
   390  					CircleCI: &ProvisionTokenSpecV2CircleCI{
   391  						Allow: []*ProvisionTokenSpecV2CircleCI_Rule{
   392  							{
   393  								ProjectID: "foo",
   394  							},
   395  						},
   396  					},
   397  				},
   398  			},
   399  			wantErr: true,
   400  		},
   401  		{
   402  			desc: "circleci allow rule blank",
   403  			token: &ProvisionTokenV2{
   404  				Metadata: Metadata{
   405  					Name: "test",
   406  				},
   407  				Spec: ProvisionTokenSpecV2{
   408  					Roles:      []SystemRole{RoleNode},
   409  					JoinMethod: JoinMethodCircleCI,
   410  					CircleCI: &ProvisionTokenSpecV2CircleCI{
   411  						Allow: []*ProvisionTokenSpecV2CircleCI_Rule{
   412  							{},
   413  						},
   414  					},
   415  				},
   416  			},
   417  			wantErr: true,
   418  		},
   419  		{
   420  			desc: "kubernetes: in_cluster defaults",
   421  			token: &ProvisionTokenV2{
   422  				Metadata: Metadata{
   423  					Name: "test",
   424  				},
   425  				Spec: ProvisionTokenSpecV2{
   426  					Roles:      []SystemRole{RoleNode},
   427  					JoinMethod: JoinMethodKubernetes,
   428  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   429  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   430  							{
   431  								ServiceAccount: "namespace:my-service-account",
   432  							},
   433  						},
   434  					},
   435  				},
   436  			},
   437  			expected: &ProvisionTokenV2{
   438  				Kind:    "token",
   439  				Version: "v2",
   440  				Metadata: Metadata{
   441  					Name:      "test",
   442  					Namespace: "default",
   443  				},
   444  				Spec: ProvisionTokenSpecV2{
   445  					Roles:      []SystemRole{RoleNode},
   446  					JoinMethod: JoinMethodKubernetes,
   447  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   448  						Type: KubernetesJoinTypeInCluster,
   449  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   450  							{
   451  								ServiceAccount: "namespace:my-service-account",
   452  							},
   453  						},
   454  					},
   455  				},
   456  			},
   457  		},
   458  		{
   459  			desc: "kubernetes: valid in_cluster",
   460  			token: &ProvisionTokenV2{
   461  				Metadata: Metadata{
   462  					Name: "test",
   463  				},
   464  				Spec: ProvisionTokenSpecV2{
   465  					Roles:      []SystemRole{RoleNode},
   466  					JoinMethod: JoinMethodKubernetes,
   467  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   468  						Type: KubernetesJoinTypeInCluster,
   469  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   470  							{
   471  								ServiceAccount: "namespace:my-service-account",
   472  							},
   473  						},
   474  					},
   475  				},
   476  			},
   477  		},
   478  		{
   479  			desc: "kubernetes: valid static_jwks",
   480  			token: &ProvisionTokenV2{
   481  				Metadata: Metadata{
   482  					Name: "test",
   483  				},
   484  				Spec: ProvisionTokenSpecV2{
   485  					Roles:      []SystemRole{RoleNode},
   486  					JoinMethod: JoinMethodKubernetes,
   487  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   488  						Type: KubernetesJoinTypeStaticJWKS,
   489  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   490  							{
   491  								ServiceAccount: "namespace:my-service-account",
   492  							},
   493  						},
   494  						StaticJWKS: &ProvisionTokenSpecV2Kubernetes_StaticJWKSConfig{
   495  							JWKS: `{"keys":[{"use":"sig","kty":"RSA","kid":"-snip-","alg":"RS256","n":"-snip-","e":"-snip-"}]}`,
   496  						},
   497  					},
   498  				},
   499  			},
   500  		},
   501  		{
   502  			desc: "kubernetes: missing static_jwks",
   503  			token: &ProvisionTokenV2{
   504  				Metadata: Metadata{
   505  					Name: "test",
   506  				},
   507  				Spec: ProvisionTokenSpecV2{
   508  					Roles:      []SystemRole{RoleNode},
   509  					JoinMethod: JoinMethodKubernetes,
   510  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   511  						Type: KubernetesJoinTypeStaticJWKS,
   512  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   513  							{
   514  								ServiceAccount: "namespace:my-service-account",
   515  							},
   516  						},
   517  					},
   518  				},
   519  			},
   520  			wantErr: true,
   521  		},
   522  		{
   523  			desc: "kubernetes: missing static_jwks.jwks",
   524  			token: &ProvisionTokenV2{
   525  				Metadata: Metadata{
   526  					Name: "test",
   527  				},
   528  				Spec: ProvisionTokenSpecV2{
   529  					Roles:      []SystemRole{RoleNode},
   530  					JoinMethod: JoinMethodKubernetes,
   531  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   532  						Type: KubernetesJoinTypeStaticJWKS,
   533  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   534  							{
   535  								ServiceAccount: "namespace:my-service-account",
   536  							},
   537  						},
   538  						StaticJWKS: &ProvisionTokenSpecV2Kubernetes_StaticJWKSConfig{},
   539  					},
   540  				},
   541  			},
   542  			wantErr: true,
   543  		},
   544  		{
   545  			desc: "kubernetes: wrong service account name",
   546  			token: &ProvisionTokenV2{
   547  				Metadata: Metadata{
   548  					Name: "test",
   549  				},
   550  				Spec: ProvisionTokenSpecV2{
   551  					Roles:      []SystemRole{RoleNode},
   552  					JoinMethod: JoinMethodKubernetes,
   553  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   554  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   555  							{
   556  								ServiceAccount: "my-service-account",
   557  							},
   558  						},
   559  					},
   560  				},
   561  			},
   562  			wantErr: true,
   563  		},
   564  		{
   565  			desc: "kubernetes: allow rule blank",
   566  			token: &ProvisionTokenV2{
   567  				Metadata: Metadata{
   568  					Name: "test",
   569  				},
   570  				Spec: ProvisionTokenSpecV2{
   571  					Roles:      []SystemRole{RoleNode},
   572  					JoinMethod: JoinMethodKubernetes,
   573  					Kubernetes: &ProvisionTokenSpecV2Kubernetes{
   574  						Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
   575  							{},
   576  						},
   577  					},
   578  				},
   579  			},
   580  			wantErr: true,
   581  		},
   582  		{
   583  			desc: "gitlab empty allow rules",
   584  			token: &ProvisionTokenV2{
   585  				Metadata: Metadata{
   586  					Name: "test",
   587  				},
   588  				Spec: ProvisionTokenSpecV2{
   589  					Roles:      []SystemRole{RoleNode},
   590  					JoinMethod: JoinMethodGitLab,
   591  					GitLab: &ProvisionTokenSpecV2GitLab{
   592  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{},
   593  					},
   594  				},
   595  			},
   596  			wantErr: true,
   597  		},
   598  		{
   599  			desc: "gitlab missing config",
   600  			token: &ProvisionTokenV2{
   601  				Metadata: Metadata{
   602  					Name: "test",
   603  				},
   604  				Spec: ProvisionTokenSpecV2{
   605  					Roles:      []SystemRole{RoleNode},
   606  					JoinMethod: JoinMethodGitLab,
   607  					GitLab:     nil,
   608  				},
   609  			},
   610  			wantErr: true,
   611  		},
   612  		{
   613  			desc: "gitlab empty allow rule",
   614  			token: &ProvisionTokenV2{
   615  				Metadata: Metadata{
   616  					Name: "test",
   617  				},
   618  				Spec: ProvisionTokenSpecV2{
   619  					Roles:      []SystemRole{RoleNode},
   620  					JoinMethod: JoinMethodGitLab,
   621  					GitLab: &ProvisionTokenSpecV2GitLab{
   622  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   623  							{},
   624  						},
   625  					},
   626  				},
   627  			},
   628  			wantErr: true,
   629  		},
   630  		{
   631  			desc: "gitlab defaults",
   632  			token: &ProvisionTokenV2{
   633  				Metadata: Metadata{
   634  					Name: "test",
   635  				},
   636  				Spec: ProvisionTokenSpecV2{
   637  					Roles:      []SystemRole{RoleNode},
   638  					JoinMethod: JoinMethodGitLab,
   639  					GitLab: &ProvisionTokenSpecV2GitLab{
   640  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   641  							{
   642  								Sub: "asub",
   643  							},
   644  						},
   645  					},
   646  				},
   647  			},
   648  			expected: &ProvisionTokenV2{
   649  				Kind:    KindToken,
   650  				Version: V2,
   651  				Metadata: Metadata{
   652  					Name:      "test",
   653  					Namespace: defaults.Namespace,
   654  				},
   655  				Spec: ProvisionTokenSpecV2{
   656  					Roles:      []SystemRole{RoleNode},
   657  					JoinMethod: JoinMethodGitLab,
   658  					GitLab: &ProvisionTokenSpecV2GitLab{
   659  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   660  							{
   661  								Sub: "asub",
   662  							},
   663  						},
   664  						Domain: defaultGitLabDomain,
   665  					},
   666  				},
   667  			},
   668  		},
   669  		{
   670  			desc: "overridden domain",
   671  			token: &ProvisionTokenV2{
   672  				Metadata: Metadata{
   673  					Name: "test",
   674  				},
   675  				Spec: ProvisionTokenSpecV2{
   676  					Roles:      []SystemRole{RoleNode},
   677  					JoinMethod: JoinMethodGitLab,
   678  					GitLab: &ProvisionTokenSpecV2GitLab{
   679  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   680  							{
   681  								Sub: "asub",
   682  							},
   683  						},
   684  						Domain: "gitlab.example.com",
   685  					},
   686  				},
   687  			},
   688  			expected: &ProvisionTokenV2{
   689  				Kind:    KindToken,
   690  				Version: V2,
   691  				Metadata: Metadata{
   692  					Name:      "test",
   693  					Namespace: defaults.Namespace,
   694  				},
   695  				Spec: ProvisionTokenSpecV2{
   696  					Roles:      []SystemRole{RoleNode},
   697  					JoinMethod: JoinMethodGitLab,
   698  					GitLab: &ProvisionTokenSpecV2GitLab{
   699  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   700  							{
   701  								Sub: "asub",
   702  							},
   703  						},
   704  						Domain: "gitlab.example.com",
   705  					},
   706  				},
   707  			},
   708  		},
   709  		{
   710  			desc: "invalid overridden domain",
   711  			token: &ProvisionTokenV2{
   712  				Metadata: Metadata{
   713  					Name: "test",
   714  				},
   715  				Spec: ProvisionTokenSpecV2{
   716  					Roles:      []SystemRole{RoleNode},
   717  					JoinMethod: JoinMethodGitLab,
   718  					GitLab: &ProvisionTokenSpecV2GitLab{
   719  						Allow: []*ProvisionTokenSpecV2GitLab_Rule{
   720  							{
   721  								Sub: "asub",
   722  							},
   723  						},
   724  						Domain: "http://gitlab.example.com",
   725  					},
   726  				},
   727  			},
   728  			wantErr: true,
   729  		},
   730  		{
   731  			desc: "spacelift",
   732  			token: &ProvisionTokenV2{
   733  				Metadata: Metadata{
   734  					Name: "test",
   735  				},
   736  				Spec: ProvisionTokenSpecV2{
   737  					Roles:      []SystemRole{RoleNode},
   738  					JoinMethod: JoinMethodSpacelift,
   739  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   740  						Hostname: "example.app.spacelift.io",
   741  						Allow: []*ProvisionTokenSpecV2Spacelift_Rule{
   742  							{
   743  								SpaceID: "foo",
   744  							},
   745  						},
   746  					},
   747  				},
   748  			},
   749  			expected: &ProvisionTokenV2{
   750  				Kind:    "token",
   751  				Version: "v2",
   752  				Metadata: Metadata{
   753  					Name:      "test",
   754  					Namespace: "default",
   755  				},
   756  				Spec: ProvisionTokenSpecV2{
   757  					Roles:      []SystemRole{RoleNode},
   758  					JoinMethod: JoinMethodSpacelift,
   759  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   760  						Hostname: "example.app.spacelift.io",
   761  						Allow: []*ProvisionTokenSpecV2Spacelift_Rule{
   762  							{
   763  								SpaceID: "foo",
   764  							},
   765  						},
   766  					},
   767  				},
   768  			},
   769  		},
   770  		{
   771  			desc: "spacelift empty allow rules",
   772  			token: &ProvisionTokenV2{
   773  				Metadata: Metadata{
   774  					Name: "test",
   775  				},
   776  				Spec: ProvisionTokenSpecV2{
   777  					Roles:      []SystemRole{RoleNode},
   778  					JoinMethod: JoinMethodSpacelift,
   779  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   780  						Hostname: "example.app.spacelift.io",
   781  						Allow:    []*ProvisionTokenSpecV2Spacelift_Rule{},
   782  					},
   783  				},
   784  			},
   785  			wantErr: true,
   786  		},
   787  		{
   788  			desc: "spacelift rule missing fields",
   789  			token: &ProvisionTokenV2{
   790  				Metadata: Metadata{
   791  					Name: "test",
   792  				},
   793  				Spec: ProvisionTokenSpecV2{
   794  					Roles:      []SystemRole{RoleNode},
   795  					JoinMethod: JoinMethodSpacelift,
   796  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   797  						Hostname: "example.app.spacelift.io",
   798  						Allow:    []*ProvisionTokenSpecV2Spacelift_Rule{{}},
   799  					},
   800  				},
   801  			},
   802  			wantErr: true,
   803  		},
   804  		{
   805  			desc: "spacelift missing hostname",
   806  			token: &ProvisionTokenV2{
   807  				Metadata: Metadata{
   808  					Name: "test",
   809  				},
   810  				Spec: ProvisionTokenSpecV2{
   811  					Roles:      []SystemRole{RoleNode},
   812  					JoinMethod: JoinMethodSpacelift,
   813  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   814  						Allow: []*ProvisionTokenSpecV2Spacelift_Rule{
   815  							{
   816  								SpaceID: "foo",
   817  							},
   818  						},
   819  					},
   820  				},
   821  			},
   822  			wantErr: true,
   823  		},
   824  		{
   825  			desc: "spacelift incorrect hostname",
   826  			token: &ProvisionTokenV2{
   827  				Metadata: Metadata{
   828  					Name: "test",
   829  				},
   830  				Spec: ProvisionTokenSpecV2{
   831  					Roles:      []SystemRole{RoleNode},
   832  					JoinMethod: JoinMethodSpacelift,
   833  					Spacelift: &ProvisionTokenSpecV2Spacelift{
   834  						Hostname: "https://example.app.spacelift.io",
   835  						Allow: []*ProvisionTokenSpecV2Spacelift_Rule{
   836  							{
   837  								SpaceID: "foo",
   838  							},
   839  						},
   840  					},
   841  				},
   842  			},
   843  			wantErr: true,
   844  		},
   845  		{
   846  			desc: "gcp method",
   847  			token: &ProvisionTokenV2{
   848  				Metadata: Metadata{
   849  					Name: "test",
   850  				},
   851  				Spec: ProvisionTokenSpecV2{
   852  					Roles:      []SystemRole{RoleNode},
   853  					JoinMethod: "gcp",
   854  					GCP: &ProvisionTokenSpecV2GCP{
   855  						Allow: []*ProvisionTokenSpecV2GCP_Rule{
   856  							{
   857  								ProjectIDs: []string{"p1"},
   858  								Locations:  []string{"us-west1-b"},
   859  							},
   860  						},
   861  					},
   862  				},
   863  			},
   864  			expected: &ProvisionTokenV2{
   865  				Kind:    "token",
   866  				Version: "v2",
   867  				Metadata: Metadata{
   868  					Name:      "test",
   869  					Namespace: "default",
   870  				},
   871  				Spec: ProvisionTokenSpecV2{
   872  					Roles:      []SystemRole{RoleNode},
   873  					JoinMethod: "gcp",
   874  					GCP: &ProvisionTokenSpecV2GCP{
   875  						Allow: []*ProvisionTokenSpecV2GCP_Rule{
   876  							{
   877  								ProjectIDs: []string{"p1"},
   878  								Locations:  []string{"us-west1-b"},
   879  							},
   880  						},
   881  					},
   882  				},
   883  			},
   884  		},
   885  		{
   886  			desc: "gcp method no project ids",
   887  			token: &ProvisionTokenV2{
   888  				Metadata: Metadata{
   889  					Name: "test",
   890  				},
   891  				Spec: ProvisionTokenSpecV2{
   892  					Roles:      []SystemRole{RoleNode},
   893  					JoinMethod: "gcp",
   894  					GCP: &ProvisionTokenSpecV2GCP{
   895  						Allow: []*ProvisionTokenSpecV2GCP_Rule{
   896  							{
   897  								Locations: []string{"us-west1-b"},
   898  							},
   899  						},
   900  					},
   901  				},
   902  			},
   903  			wantErr: true,
   904  		},
   905  		{
   906  			desc: "tpm success with CA",
   907  			token: &ProvisionTokenV2{
   908  				Metadata: Metadata{
   909  					Name: "test",
   910  				},
   911  				Spec: ProvisionTokenSpecV2{
   912  					Roles:      []SystemRole{RoleNode},
   913  					JoinMethod: JoinMethodTPM,
   914  					TPM: &ProvisionTokenSpecV2TPM{
   915  						EKCertAllowedCAs: []string{fixtures.TLSCACertPEM},
   916  						Allow: []*ProvisionTokenSpecV2TPM_Rule{
   917  							{
   918  								Description:  "my description",
   919  								EKPublicHash: "d4b45864d9d6fabfc568d74f26c35ababde2105337d7af9a6605e1c56c891aa6",
   920  							},
   921  							{
   922  								EKCertificateSerial: "73:df:dc:bd:af:ef:8a:d8:15:2e:96:71:7a:3e:7f:a4",
   923  							},
   924  							{
   925  								EKPublicHash:        "d4b45864d9d6fabfc568d74f26c35ababde2105337d7af9a6605e1c56c891aa6",
   926  								EKCertificateSerial: "73:df:dc:bd:af:ef:8a:d8:15:2e:96:71:7a:3e:7f:a4",
   927  							},
   928  						},
   929  					},
   930  				},
   931  			},
   932  			wantErr: false,
   933  		},
   934  		{
   935  			desc: "tpm success without CA",
   936  			token: &ProvisionTokenV2{
   937  				Metadata: Metadata{
   938  					Name: "test",
   939  				},
   940  				Spec: ProvisionTokenSpecV2{
   941  					Roles:      []SystemRole{RoleNode},
   942  					JoinMethod: JoinMethodTPM,
   943  					TPM: &ProvisionTokenSpecV2TPM{
   944  						Allow: []*ProvisionTokenSpecV2TPM_Rule{
   945  							{
   946  								Description:  "my description",
   947  								EKPublicHash: "d4b45864d9d6fabfc568d74f26c35ababde2105337d7af9a6605e1c56c891aa6",
   948  							},
   949  							{
   950  								EKCertificateSerial: "73:df:dc:bd:af:ef:8a:d8:15:2e:96:71:7a:3e:7f:a4",
   951  							},
   952  							{
   953  								EKPublicHash:        "d4b45864d9d6fabfc568d74f26c35ababde2105337d7af9a6605e1c56c891aa6",
   954  								EKCertificateSerial: "73:df:dc:bd:af:ef:8a:d8:15:2e:96:71:7a:3e:7f:a4",
   955  							},
   956  						},
   957  					},
   958  				},
   959  			},
   960  			wantErr: false,
   961  		},
   962  		{
   963  			desc: "tpm corrupt CA",
   964  			token: &ProvisionTokenV2{
   965  				Metadata: Metadata{
   966  					Name: "test",
   967  				},
   968  				Spec: ProvisionTokenSpecV2{
   969  					Roles:      []SystemRole{RoleNode},
   970  					JoinMethod: JoinMethodTPM,
   971  					TPM: &ProvisionTokenSpecV2TPM{
   972  						EKCertAllowedCAs: []string{"corrupt"},
   973  						Allow: []*ProvisionTokenSpecV2TPM_Rule{
   974  							{
   975  								Description:  "my description",
   976  								EKPublicHash: "d4b45864d9d6fabfc568d74f26c35ababde2105337d7af9a6605e1c56c891aa6",
   977  							},
   978  						},
   979  					},
   980  				},
   981  			},
   982  			wantErr: true,
   983  		},
   984  		{
   985  			desc: "tpm missing rules",
   986  			token: &ProvisionTokenV2{
   987  				Metadata: Metadata{
   988  					Name: "test",
   989  				},
   990  				Spec: ProvisionTokenSpecV2{
   991  					Roles:      []SystemRole{RoleNode},
   992  					JoinMethod: JoinMethodTPM,
   993  					TPM: &ProvisionTokenSpecV2TPM{
   994  						EKCertAllowedCAs: []string{},
   995  						Allow:            []*ProvisionTokenSpecV2TPM_Rule{},
   996  					},
   997  				},
   998  			},
   999  			wantErr: true,
  1000  		},
  1001  		{
  1002  			desc: "tpm rule without ekpubhash or ekcertserial",
  1003  			token: &ProvisionTokenV2{
  1004  				Metadata: Metadata{
  1005  					Name: "test",
  1006  				},
  1007  				Spec: ProvisionTokenSpecV2{
  1008  					Roles:      []SystemRole{RoleNode},
  1009  					JoinMethod: JoinMethodTPM,
  1010  					TPM: &ProvisionTokenSpecV2TPM{
  1011  						EKCertAllowedCAs: []string{},
  1012  						Allow: []*ProvisionTokenSpecV2TPM_Rule{
  1013  							{
  1014  								Description: "my description",
  1015  							},
  1016  						},
  1017  					},
  1018  				},
  1019  			},
  1020  			wantErr: true,
  1021  		},
  1022  	}
  1023  
  1024  	for _, tc := range testcases {
  1025  		t.Run(tc.desc, func(t *testing.T) {
  1026  			err := tc.token.CheckAndSetDefaults()
  1027  			if tc.wantErr {
  1028  				require.Error(t, err)
  1029  				require.True(t,
  1030  					trace.IsBadParameter(err),
  1031  					"want BadParameter, got %v (%T)", err, trace.Unwrap(err))
  1032  				return
  1033  			}
  1034  			require.NoError(t, err)
  1035  
  1036  			if tc.expected != nil {
  1037  				require.Equal(t, tc.expected, tc.token)
  1038  			}
  1039  		})
  1040  	}
  1041  }
  1042  
  1043  func TestProvisionTokenV2_GetSafeName(t *testing.T) {
  1044  	t.Run("token join method (short)", func(t *testing.T) {
  1045  		tok, err := NewProvisionToken("1234", []SystemRole{RoleNode}, time.Now())
  1046  		require.NoError(t, err)
  1047  		got := tok.GetSafeName()
  1048  		require.Equal(t, "****", got)
  1049  	})
  1050  	t.Run("token join method (long)", func(t *testing.T) {
  1051  		tok, err := NewProvisionToken("0123456789abcdef", []SystemRole{RoleNode}, time.Now())
  1052  		require.NoError(t, err)
  1053  		got := tok.GetSafeName()
  1054  		require.Equal(t, "************cdef", got)
  1055  	})
  1056  	t.Run("non-token join method", func(t *testing.T) {
  1057  		tok, err := NewProvisionTokenFromSpec("12345678", time.Now(), ProvisionTokenSpecV2{
  1058  			Roles:      []SystemRole{RoleNode},
  1059  			JoinMethod: JoinMethodKubernetes,
  1060  			Kubernetes: &ProvisionTokenSpecV2Kubernetes{
  1061  				Allow: []*ProvisionTokenSpecV2Kubernetes_Rule{
  1062  					{
  1063  						ServiceAccount: "namespace:my-service-account",
  1064  					},
  1065  				},
  1066  			},
  1067  		})
  1068  		require.NoError(t, err)
  1069  		got := tok.GetSafeName()
  1070  		require.Equal(t, "12345678", got)
  1071  	})
  1072  }
  1073  
  1074  func TestProvisionTokenV2_CaseInsensitiveRoles(t *testing.T) {
  1075  	t.Parallel()
  1076  	t.Run("via constructor", func(t *testing.T) {
  1077  		tok, err := NewProvisionToken("token", SystemRoles{"nOde", "AuTh"}, time.Now())
  1078  		require.NoError(t, err)
  1079  		require.Equal(t, SystemRoles{RoleNode, RoleAuth}, tok.GetRoles())
  1080  	})
  1081  	t.Run("via struct", func(t *testing.T) {
  1082  		tok := &ProvisionTokenV2{
  1083  			Spec: ProvisionTokenSpecV2{
  1084  				Roles: []SystemRole{"nOdE", "AuTh"},
  1085  			},
  1086  		}
  1087  		require.Equal(t, SystemRoles{RoleNode, RoleAuth}, tok.GetRoles())
  1088  	})
  1089  }
  1090  
  1091  func TestProvisionTokenV2_SignupRole(t *testing.T) {
  1092  	t.Parallel()
  1093  	tok, err := NewProvisionToken("token", SystemRoles{RoleSignup}, time.Now())
  1094  	require.NoError(t, err)
  1095  	require.Equal(t, SystemRoles{RoleSignup}, tok.GetRoles())
  1096  }