Add Env0 join method (#60386)

* Add Env0 method

This adds a new `env0` join method to support joining from env0
workflows, and especially the embedded tbot in the Terraform provider
when running on env0.

This is the first OIDC join method on the new join service, and will
not support legacy joining. As such, it won't be backported beyond
v18.

Closes #53798

changelog: Add new `env0` join method to support joining within Env0 workflows

* Fix imports

* Fix failing test

* Add env0 token source

* Fix missing env0 join method in tbot

* Fix env0 validation

This fixes some issues in env0 token validation:
- azp check is disabled since it's set to a random (ish) value
- Use correct audience URL (their docs specified the wrong value)

* Fix incorrect date in new file copyright header

* Fix generated tfschema

* Fix failing test after adding the token source

* First round of code review

* Add example token claims in comment

* Move common OIDC handling logic into a separate handler

Specific validation logic is now separate and the validator is passed
as an argument to a generic `handleOIDCJoin()` handler.

* Fix imports

* Rename joinclient/join_env0.go to join_oidc.go
This commit is contained in:
Tim Buckley
2025-10-27 23:02:20 +00:00
committed by GitHub
parent 7101c6d4ef
commit dfc545a62c
32 changed files with 6363 additions and 2993 deletions
@@ -93,7 +93,7 @@ func (x GivingUp_Reason) Number() protoreflect.EnumNumber {
// Deprecated: Use GivingUp_Reason.Descriptor instead.
func (GivingUp_Reason) EnumDescriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{17, 0}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{18, 0}
}
// ClientInit is the first message sent from the client during the join process, it
@@ -510,6 +510,67 @@ func (x *TokenInit) GetClientParams() *ClientParams {
return nil
}
// OIDCInit holds the OIDC identity token used for all OIDC-based join methods.
//
// The join flow for all OIDC-based join methods is:
// 1. client->server: ClientInit
// 2. server->client: ServerInit
// 3. client->server: OIDCInit
// 4. server->client: Result
type OIDCInit struct {
state protoimpl.MessageState `protogen:"open.v1"`
// ClientParams holds parameters for the specific type of client trying to join.
ClientParams *ClientParams `protobuf:"bytes,1,opt,name=client_params,json=clientParams,proto3" json:"client_params,omitempty"`
// IdToken is the OIDC identity token.
IdToken []byte `protobuf:"bytes,2,opt,name=id_token,json=idToken,proto3" json:"id_token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *OIDCInit) Reset() {
*x = OIDCInit{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *OIDCInit) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*OIDCInit) ProtoMessage() {}
func (x *OIDCInit) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use OIDCInit.ProtoReflect.Descriptor instead.
func (*OIDCInit) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{6}
}
func (x *OIDCInit) GetClientParams() *ClientParams {
if x != nil {
return x.ClientParams
}
return nil
}
func (x *OIDCInit) GetIdToken() []byte {
if x != nil {
return x.IdToken
}
return nil
}
// BoundKeypairInit is sent from the client in response to the ServerInit
// message for the bound keypair join method.
// The server is expected to respond with a BoundKeypairChallenge.
@@ -543,7 +604,7 @@ type BoundKeypairInit struct {
func (x *BoundKeypairInit) Reset() {
*x = BoundKeypairInit{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[6]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -555,7 +616,7 @@ func (x *BoundKeypairInit) String() string {
func (*BoundKeypairInit) ProtoMessage() {}
func (x *BoundKeypairInit) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[6]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -568,7 +629,7 @@ func (x *BoundKeypairInit) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairInit.ProtoReflect.Descriptor instead.
func (*BoundKeypairInit) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{6}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{7}
}
func (x *BoundKeypairInit) GetClientParams() *ClientParams {
@@ -610,7 +671,7 @@ type BoundKeypairChallenge struct {
func (x *BoundKeypairChallenge) Reset() {
*x = BoundKeypairChallenge{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[7]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -622,7 +683,7 @@ func (x *BoundKeypairChallenge) String() string {
func (*BoundKeypairChallenge) ProtoMessage() {}
func (x *BoundKeypairChallenge) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[7]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -635,7 +696,7 @@ func (x *BoundKeypairChallenge) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairChallenge.ProtoReflect.Descriptor instead.
func (*BoundKeypairChallenge) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{7}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{8}
}
func (x *BoundKeypairChallenge) GetPublicKey() []byte {
@@ -668,7 +729,7 @@ type BoundKeypairChallengeSolution struct {
func (x *BoundKeypairChallengeSolution) Reset() {
*x = BoundKeypairChallengeSolution{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[8]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -680,7 +741,7 @@ func (x *BoundKeypairChallengeSolution) String() string {
func (*BoundKeypairChallengeSolution) ProtoMessage() {}
func (x *BoundKeypairChallengeSolution) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[8]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -693,7 +754,7 @@ func (x *BoundKeypairChallengeSolution) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairChallengeSolution.ProtoReflect.Descriptor instead.
func (*BoundKeypairChallengeSolution) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{8}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{9}
}
func (x *BoundKeypairChallengeSolution) GetSolution() []byte {
@@ -717,7 +778,7 @@ type BoundKeypairRotationRequest struct {
func (x *BoundKeypairRotationRequest) Reset() {
*x = BoundKeypairRotationRequest{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[9]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -729,7 +790,7 @@ func (x *BoundKeypairRotationRequest) String() string {
func (*BoundKeypairRotationRequest) ProtoMessage() {}
func (x *BoundKeypairRotationRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[9]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -742,7 +803,7 @@ func (x *BoundKeypairRotationRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairRotationRequest.ProtoReflect.Descriptor instead.
func (*BoundKeypairRotationRequest) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{9}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{10}
}
func (x *BoundKeypairRotationRequest) GetSignatureAlgorithmSuite() string {
@@ -768,7 +829,7 @@ type BoundKeypairRotationResponse struct {
func (x *BoundKeypairRotationResponse) Reset() {
*x = BoundKeypairRotationResponse{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[10]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -780,7 +841,7 @@ func (x *BoundKeypairRotationResponse) String() string {
func (*BoundKeypairRotationResponse) ProtoMessage() {}
func (x *BoundKeypairRotationResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[10]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -793,7 +854,7 @@ func (x *BoundKeypairRotationResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairRotationResponse.ProtoReflect.Descriptor instead.
func (*BoundKeypairRotationResponse) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{10}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{11}
}
func (x *BoundKeypairRotationResponse) GetPublicKey() []byte {
@@ -819,7 +880,7 @@ type BoundKeypairResult struct {
func (x *BoundKeypairResult) Reset() {
*x = BoundKeypairResult{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[11]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -831,7 +892,7 @@ func (x *BoundKeypairResult) String() string {
func (*BoundKeypairResult) ProtoMessage() {}
func (x *BoundKeypairResult) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[11]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -844,7 +905,7 @@ func (x *BoundKeypairResult) ProtoReflect() protoreflect.Message {
// Deprecated: Use BoundKeypairResult.ProtoReflect.Descriptor instead.
func (*BoundKeypairResult) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{11}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{12}
}
func (x *BoundKeypairResult) GetJoinState() []byte {
@@ -881,7 +942,7 @@ type IAMInit struct {
func (x *IAMInit) Reset() {
*x = IAMInit{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[12]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -893,7 +954,7 @@ func (x *IAMInit) String() string {
func (*IAMInit) ProtoMessage() {}
func (x *IAMInit) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[12]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -906,7 +967,7 @@ func (x *IAMInit) ProtoReflect() protoreflect.Message {
// Deprecated: Use IAMInit.ProtoReflect.Descriptor instead.
func (*IAMInit) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{12}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{13}
}
func (x *IAMInit) GetClientParams() *ClientParams {
@@ -929,7 +990,7 @@ type IAMChallenge struct {
func (x *IAMChallenge) Reset() {
*x = IAMChallenge{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[13]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -941,7 +1002,7 @@ func (x *IAMChallenge) String() string {
func (*IAMChallenge) ProtoMessage() {}
func (x *IAMChallenge) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[13]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -954,7 +1015,7 @@ func (x *IAMChallenge) ProtoReflect() protoreflect.Message {
// Deprecated: Use IAMChallenge.ProtoReflect.Descriptor instead.
func (*IAMChallenge) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{13}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{14}
}
func (x *IAMChallenge) GetChallenge() string {
@@ -978,7 +1039,7 @@ type IAMChallengeSolution struct {
func (x *IAMChallengeSolution) Reset() {
*x = IAMChallengeSolution{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[14]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -990,7 +1051,7 @@ func (x *IAMChallengeSolution) String() string {
func (*IAMChallengeSolution) ProtoMessage() {}
func (x *IAMChallengeSolution) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[14]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1003,7 +1064,7 @@ func (x *IAMChallengeSolution) ProtoReflect() protoreflect.Message {
// Deprecated: Use IAMChallengeSolution.ProtoReflect.Descriptor instead.
func (*IAMChallengeSolution) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{14}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{15}
}
func (x *IAMChallengeSolution) GetStsIdentityRequest() []byte {
@@ -1034,7 +1095,7 @@ type EC2Init struct {
func (x *EC2Init) Reset() {
*x = EC2Init{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[15]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1046,7 +1107,7 @@ func (x *EC2Init) String() string {
func (*EC2Init) ProtoMessage() {}
func (x *EC2Init) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[15]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1059,7 +1120,7 @@ func (x *EC2Init) ProtoReflect() protoreflect.Message {
// Deprecated: Use EC2Init.ProtoReflect.Descriptor instead.
func (*EC2Init) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{15}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{16}
}
func (x *EC2Init) GetClientParams() *ClientParams {
@@ -1091,7 +1152,7 @@ type ChallengeSolution struct {
func (x *ChallengeSolution) Reset() {
*x = ChallengeSolution{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[16]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1103,7 +1164,7 @@ func (x *ChallengeSolution) String() string {
func (*ChallengeSolution) ProtoMessage() {}
func (x *ChallengeSolution) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[16]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1116,7 +1177,7 @@ func (x *ChallengeSolution) ProtoReflect() protoreflect.Message {
// Deprecated: Use ChallengeSolution.ProtoReflect.Descriptor instead.
func (*ChallengeSolution) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{16}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{17}
}
func (x *ChallengeSolution) GetPayload() isChallengeSolution_Payload {
@@ -1189,7 +1250,7 @@ type GivingUp struct {
func (x *GivingUp) Reset() {
*x = GivingUp{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[17]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1201,7 +1262,7 @@ func (x *GivingUp) String() string {
func (*GivingUp) ProtoMessage() {}
func (x *GivingUp) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[17]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1214,7 +1275,7 @@ func (x *GivingUp) ProtoReflect() protoreflect.Message {
// Deprecated: Use GivingUp.ProtoReflect.Descriptor instead.
func (*GivingUp) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{17}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{18}
}
func (x *GivingUp) GetReason() GivingUp_Reason {
@@ -1243,6 +1304,7 @@ type JoinRequest struct {
// *JoinRequest_IamInit
// *JoinRequest_GivingUp
// *JoinRequest_Ec2Init
// *JoinRequest_OidcInit
Payload isJoinRequest_Payload `protobuf_oneof:"payload"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@@ -1250,7 +1312,7 @@ type JoinRequest struct {
func (x *JoinRequest) Reset() {
*x = JoinRequest{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[18]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1262,7 +1324,7 @@ func (x *JoinRequest) String() string {
func (*JoinRequest) ProtoMessage() {}
func (x *JoinRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[18]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1275,7 +1337,7 @@ func (x *JoinRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use JoinRequest.ProtoReflect.Descriptor instead.
func (*JoinRequest) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{18}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{19}
}
func (x *JoinRequest) GetPayload() isJoinRequest_Payload {
@@ -1348,6 +1410,15 @@ func (x *JoinRequest) GetEc2Init() *EC2Init {
return nil
}
func (x *JoinRequest) GetOidcInit() *OIDCInit {
if x != nil {
if x, ok := x.Payload.(*JoinRequest_OidcInit); ok {
return x.OidcInit
}
}
return nil
}
type isJoinRequest_Payload interface {
isJoinRequest_Payload()
}
@@ -1380,6 +1451,10 @@ type JoinRequest_Ec2Init struct {
Ec2Init *EC2Init `protobuf:"bytes,7,opt,name=ec2_init,json=ec2Init,proto3,oneof"`
}
type JoinRequest_OidcInit struct {
OidcInit *OIDCInit `protobuf:"bytes,8,opt,name=oidc_init,json=oidcInit,proto3,oneof"`
}
func (*JoinRequest_ClientInit) isJoinRequest_Payload() {}
func (*JoinRequest_TokenInit) isJoinRequest_Payload() {}
@@ -1394,6 +1469,8 @@ func (*JoinRequest_GivingUp) isJoinRequest_Payload() {}
func (*JoinRequest_Ec2Init) isJoinRequest_Payload() {}
func (*JoinRequest_OidcInit) isJoinRequest_Payload() {}
// ServerInit is the first message sent from the server in response to the
// ClientInit message.
type ServerInit struct {
@@ -1409,7 +1486,7 @@ type ServerInit struct {
func (x *ServerInit) Reset() {
*x = ServerInit{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[19]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1421,7 +1498,7 @@ func (x *ServerInit) String() string {
func (*ServerInit) ProtoMessage() {}
func (x *ServerInit) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[19]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1434,7 +1511,7 @@ func (x *ServerInit) ProtoReflect() protoreflect.Message {
// Deprecated: Use ServerInit.ProtoReflect.Descriptor instead.
func (*ServerInit) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{19}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{20}
}
func (x *ServerInit) GetJoinMethod() string {
@@ -1466,7 +1543,7 @@ type Challenge struct {
func (x *Challenge) Reset() {
*x = Challenge{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[20]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1478,7 +1555,7 @@ func (x *Challenge) String() string {
func (*Challenge) ProtoMessage() {}
func (x *Challenge) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[20]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1491,7 +1568,7 @@ func (x *Challenge) ProtoReflect() protoreflect.Message {
// Deprecated: Use Challenge.ProtoReflect.Descriptor instead.
func (*Challenge) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{20}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{21}
}
func (x *Challenge) GetPayload() isChallenge_Payload {
@@ -1566,7 +1643,7 @@ type Result struct {
func (x *Result) Reset() {
*x = Result{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[21]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1578,7 +1655,7 @@ func (x *Result) String() string {
func (*Result) ProtoMessage() {}
func (x *Result) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[21]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1591,7 +1668,7 @@ func (x *Result) ProtoReflect() protoreflect.Message {
// Deprecated: Use Result.ProtoReflect.Descriptor instead.
func (*Result) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{21}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{22}
}
func (x *Result) GetPayload() isResult_Payload {
@@ -1654,7 +1731,7 @@ type Certificates struct {
func (x *Certificates) Reset() {
*x = Certificates{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[22]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1666,7 +1743,7 @@ func (x *Certificates) String() string {
func (*Certificates) ProtoMessage() {}
func (x *Certificates) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[22]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1679,7 +1756,7 @@ func (x *Certificates) ProtoReflect() protoreflect.Message {
// Deprecated: Use Certificates.ProtoReflect.Descriptor instead.
func (*Certificates) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{22}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{23}
}
func (x *Certificates) GetTlsCert() []byte {
@@ -1723,7 +1800,7 @@ type HostResult struct {
func (x *HostResult) Reset() {
*x = HostResult{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[23]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1735,7 +1812,7 @@ func (x *HostResult) String() string {
func (*HostResult) ProtoMessage() {}
func (x *HostResult) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[23]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1748,7 +1825,7 @@ func (x *HostResult) ProtoReflect() protoreflect.Message {
// Deprecated: Use HostResult.ProtoReflect.Descriptor instead.
func (*HostResult) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{23}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{24}
}
func (x *HostResult) GetCertificates() *Certificates {
@@ -1778,7 +1855,7 @@ type BotResult struct {
func (x *BotResult) Reset() {
*x = BotResult{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[24]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1790,7 +1867,7 @@ func (x *BotResult) String() string {
func (*BotResult) ProtoMessage() {}
func (x *BotResult) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[24]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1803,7 +1880,7 @@ func (x *BotResult) ProtoReflect() protoreflect.Message {
// Deprecated: Use BotResult.ProtoReflect.Descriptor instead.
func (*BotResult) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{24}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{25}
}
func (x *BotResult) GetCertificates() *Certificates {
@@ -1835,7 +1912,7 @@ type JoinResponse struct {
func (x *JoinResponse) Reset() {
*x = JoinResponse{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[25]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1847,7 +1924,7 @@ func (x *JoinResponse) String() string {
func (*JoinResponse) ProtoMessage() {}
func (x *JoinResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[25]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[26]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1860,7 +1937,7 @@ func (x *JoinResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use JoinResponse.ProtoReflect.Descriptor instead.
func (*JoinResponse) Descriptor() ([]byte, []int) {
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{25}
return file_teleport_join_v1_joinservice_proto_rawDescGZIP(), []int{26}
}
func (x *JoinResponse) GetPayload() isJoinResponse_Payload {
@@ -1943,7 +2020,7 @@ type ClientInit_ProxySuppliedParams struct {
func (x *ClientInit_ProxySuppliedParams) Reset() {
*x = ClientInit_ProxySuppliedParams{}
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[26]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1955,7 +2032,7 @@ func (x *ClientInit_ProxySuppliedParams) String() string {
func (*ClientInit_ProxySuppliedParams) ProtoMessage() {}
func (x *ClientInit_ProxySuppliedParams) ProtoReflect() protoreflect.Message {
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[26]
mi := &file_teleport_join_v1_joinservice_proto_msgTypes[27]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -2030,7 +2107,10 @@ const file_teleport_join_v1_joinservice_proto_rawDesc = "" +
"bot_params\x18\x02 \x01(\v2\x1b.teleport.join.v1.BotParamsH\x00R\tbotParamsB\t\n" +
"\apayload\"P\n" +
"\tTokenInit\x12C\n" +
"\rclient_params\x18\x01 \x01(\v2\x1e.teleport.join.v1.ClientParamsR\fclientParams\"\xb7\x01\n" +
"\rclient_params\x18\x01 \x01(\v2\x1e.teleport.join.v1.ClientParamsR\fclientParams\"j\n" +
"\bOIDCInit\x12C\n" +
"\rclient_params\x18\x01 \x01(\v2\x1e.teleport.join.v1.ClientParamsR\fclientParams\x12\x19\n" +
"\bid_token\x18\x02 \x01(\fR\aidToken\"\xb7\x01\n" +
"\x10BoundKeypairInit\x12C\n" +
"\rclient_params\x18\x01 \x01(\v2\x1e.teleport.join.v1.ClientParamsR\fclientParams\x12.\n" +
"\x13initial_join_secret\x18\x02 \x01(\tR\x11initialJoinSecret\x12.\n" +
@@ -2072,7 +2152,7 @@ const file_teleport_join_v1_joinservice_proto_rawDesc = "" +
"\x12REASON_UNSPECIFIED\x10\x00\x12\"\n" +
"\x1eREASON_UNSUPPORTED_JOIN_METHOD\x10\x01\x12#\n" +
"\x1fREASON_UNSUPPORTED_MESSAGE_TYPE\x10\x02\x12$\n" +
" REASON_CHALLENGE_SOLUTION_FAILED\x10\x03\"\xd9\x03\n" +
" REASON_CHALLENGE_SOLUTION_FAILED\x10\x03\"\x94\x04\n" +
"\vJoinRequest\x12?\n" +
"\vclient_init\x18\x01 \x01(\v2\x1c.teleport.join.v1.ClientInitH\x00R\n" +
"clientInit\x12<\n" +
@@ -2082,7 +2162,8 @@ const file_teleport_join_v1_joinservice_proto_rawDesc = "" +
"\bsolution\x18\x04 \x01(\v2#.teleport.join.v1.ChallengeSolutionH\x00R\bsolution\x126\n" +
"\biam_init\x18\x05 \x01(\v2\x19.teleport.join.v1.IAMInitH\x00R\aiamInit\x129\n" +
"\tgiving_up\x18\x06 \x01(\v2\x1a.teleport.join.v1.GivingUpH\x00R\bgivingUp\x126\n" +
"\bec2_init\x18\a \x01(\v2\x19.teleport.join.v1.EC2InitH\x00R\aec2InitB\t\n" +
"\bec2_init\x18\a \x01(\v2\x19.teleport.join.v1.EC2InitH\x00R\aec2Init\x129\n" +
"\toidc_init\x18\b \x01(\v2\x1a.teleport.join.v1.OIDCInitH\x00R\boidcInitB\t\n" +
"\apayload\"i\n" +
"\n" +
"ServerInit\x12\x1f\n" +
@@ -2135,7 +2216,7 @@ func file_teleport_join_v1_joinservice_proto_rawDescGZIP() []byte {
}
var file_teleport_join_v1_joinservice_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_teleport_join_v1_joinservice_proto_msgTypes = make([]protoimpl.MessageInfo, 27)
var file_teleport_join_v1_joinservice_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
var file_teleport_join_v1_joinservice_proto_goTypes = []any{
(GivingUp_Reason)(0), // 0: teleport.join.v1.GivingUp.Reason
(*ClientInit)(nil), // 1: teleport.join.v1.ClientInit
@@ -2144,69 +2225,72 @@ var file_teleport_join_v1_joinservice_proto_goTypes = []any{
(*BotParams)(nil), // 4: teleport.join.v1.BotParams
(*ClientParams)(nil), // 5: teleport.join.v1.ClientParams
(*TokenInit)(nil), // 6: teleport.join.v1.TokenInit
(*BoundKeypairInit)(nil), // 7: teleport.join.v1.BoundKeypairInit
(*BoundKeypairChallenge)(nil), // 8: teleport.join.v1.BoundKeypairChallenge
(*BoundKeypairChallengeSolution)(nil), // 9: teleport.join.v1.BoundKeypairChallengeSolution
(*BoundKeypairRotationRequest)(nil), // 10: teleport.join.v1.BoundKeypairRotationRequest
(*BoundKeypairRotationResponse)(nil), // 11: teleport.join.v1.BoundKeypairRotationResponse
(*BoundKeypairResult)(nil), // 12: teleport.join.v1.BoundKeypairResult
(*IAMInit)(nil), // 13: teleport.join.v1.IAMInit
(*IAMChallenge)(nil), // 14: teleport.join.v1.IAMChallenge
(*IAMChallengeSolution)(nil), // 15: teleport.join.v1.IAMChallengeSolution
(*EC2Init)(nil), // 16: teleport.join.v1.EC2Init
(*ChallengeSolution)(nil), // 17: teleport.join.v1.ChallengeSolution
(*GivingUp)(nil), // 18: teleport.join.v1.GivingUp
(*JoinRequest)(nil), // 19: teleport.join.v1.JoinRequest
(*ServerInit)(nil), // 20: teleport.join.v1.ServerInit
(*Challenge)(nil), // 21: teleport.join.v1.Challenge
(*Result)(nil), // 22: teleport.join.v1.Result
(*Certificates)(nil), // 23: teleport.join.v1.Certificates
(*HostResult)(nil), // 24: teleport.join.v1.HostResult
(*BotResult)(nil), // 25: teleport.join.v1.BotResult
(*JoinResponse)(nil), // 26: teleport.join.v1.JoinResponse
(*ClientInit_ProxySuppliedParams)(nil), // 27: teleport.join.v1.ClientInit.ProxySuppliedParams
(*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp
(*OIDCInit)(nil), // 7: teleport.join.v1.OIDCInit
(*BoundKeypairInit)(nil), // 8: teleport.join.v1.BoundKeypairInit
(*BoundKeypairChallenge)(nil), // 9: teleport.join.v1.BoundKeypairChallenge
(*BoundKeypairChallengeSolution)(nil), // 10: teleport.join.v1.BoundKeypairChallengeSolution
(*BoundKeypairRotationRequest)(nil), // 11: teleport.join.v1.BoundKeypairRotationRequest
(*BoundKeypairRotationResponse)(nil), // 12: teleport.join.v1.BoundKeypairRotationResponse
(*BoundKeypairResult)(nil), // 13: teleport.join.v1.BoundKeypairResult
(*IAMInit)(nil), // 14: teleport.join.v1.IAMInit
(*IAMChallenge)(nil), // 15: teleport.join.v1.IAMChallenge
(*IAMChallengeSolution)(nil), // 16: teleport.join.v1.IAMChallengeSolution
(*EC2Init)(nil), // 17: teleport.join.v1.EC2Init
(*ChallengeSolution)(nil), // 18: teleport.join.v1.ChallengeSolution
(*GivingUp)(nil), // 19: teleport.join.v1.GivingUp
(*JoinRequest)(nil), // 20: teleport.join.v1.JoinRequest
(*ServerInit)(nil), // 21: teleport.join.v1.ServerInit
(*Challenge)(nil), // 22: teleport.join.v1.Challenge
(*Result)(nil), // 23: teleport.join.v1.Result
(*Certificates)(nil), // 24: teleport.join.v1.Certificates
(*HostResult)(nil), // 25: teleport.join.v1.HostResult
(*BotResult)(nil), // 26: teleport.join.v1.BotResult
(*JoinResponse)(nil), // 27: teleport.join.v1.JoinResponse
(*ClientInit_ProxySuppliedParams)(nil), // 28: teleport.join.v1.ClientInit.ProxySuppliedParams
(*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp
}
var file_teleport_join_v1_joinservice_proto_depIdxs = []int32{
27, // 0: teleport.join.v1.ClientInit.proxy_supplied_parameters:type_name -> teleport.join.v1.ClientInit.ProxySuppliedParams
28, // 0: teleport.join.v1.ClientInit.proxy_supplied_parameters:type_name -> teleport.join.v1.ClientInit.ProxySuppliedParams
2, // 1: teleport.join.v1.HostParams.public_keys:type_name -> teleport.join.v1.PublicKeys
2, // 2: teleport.join.v1.BotParams.public_keys:type_name -> teleport.join.v1.PublicKeys
28, // 3: teleport.join.v1.BotParams.expires:type_name -> google.protobuf.Timestamp
29, // 3: teleport.join.v1.BotParams.expires:type_name -> google.protobuf.Timestamp
3, // 4: teleport.join.v1.ClientParams.host_params:type_name -> teleport.join.v1.HostParams
4, // 5: teleport.join.v1.ClientParams.bot_params:type_name -> teleport.join.v1.BotParams
5, // 6: teleport.join.v1.TokenInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 7: teleport.join.v1.BoundKeypairInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 8: teleport.join.v1.IAMInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 9: teleport.join.v1.EC2Init.client_params:type_name -> teleport.join.v1.ClientParams
9, // 10: teleport.join.v1.ChallengeSolution.bound_keypair_challenge_solution:type_name -> teleport.join.v1.BoundKeypairChallengeSolution
11, // 11: teleport.join.v1.ChallengeSolution.bound_keypair_rotation_response:type_name -> teleport.join.v1.BoundKeypairRotationResponse
15, // 12: teleport.join.v1.ChallengeSolution.iam_challenge_solution:type_name -> teleport.join.v1.IAMChallengeSolution
0, // 13: teleport.join.v1.GivingUp.reason:type_name -> teleport.join.v1.GivingUp.Reason
1, // 14: teleport.join.v1.JoinRequest.client_init:type_name -> teleport.join.v1.ClientInit
6, // 15: teleport.join.v1.JoinRequest.token_init:type_name -> teleport.join.v1.TokenInit
7, // 16: teleport.join.v1.JoinRequest.bound_keypair_init:type_name -> teleport.join.v1.BoundKeypairInit
17, // 17: teleport.join.v1.JoinRequest.solution:type_name -> teleport.join.v1.ChallengeSolution
13, // 18: teleport.join.v1.JoinRequest.iam_init:type_name -> teleport.join.v1.IAMInit
18, // 19: teleport.join.v1.JoinRequest.giving_up:type_name -> teleport.join.v1.GivingUp
16, // 20: teleport.join.v1.JoinRequest.ec2_init:type_name -> teleport.join.v1.EC2Init
8, // 21: teleport.join.v1.Challenge.bound_keypair_challenge:type_name -> teleport.join.v1.BoundKeypairChallenge
10, // 22: teleport.join.v1.Challenge.bound_keypair_rotation_request:type_name -> teleport.join.v1.BoundKeypairRotationRequest
14, // 23: teleport.join.v1.Challenge.iam_challenge:type_name -> teleport.join.v1.IAMChallenge
24, // 24: teleport.join.v1.Result.host_result:type_name -> teleport.join.v1.HostResult
25, // 25: teleport.join.v1.Result.bot_result:type_name -> teleport.join.v1.BotResult
23, // 26: teleport.join.v1.HostResult.certificates:type_name -> teleport.join.v1.Certificates
23, // 27: teleport.join.v1.BotResult.certificates:type_name -> teleport.join.v1.Certificates
12, // 28: teleport.join.v1.BotResult.bound_keypair_result:type_name -> teleport.join.v1.BoundKeypairResult
20, // 29: teleport.join.v1.JoinResponse.init:type_name -> teleport.join.v1.ServerInit
21, // 30: teleport.join.v1.JoinResponse.challenge:type_name -> teleport.join.v1.Challenge
22, // 31: teleport.join.v1.JoinResponse.result:type_name -> teleport.join.v1.Result
19, // 32: teleport.join.v1.JoinService.Join:input_type -> teleport.join.v1.JoinRequest
26, // 33: teleport.join.v1.JoinService.Join:output_type -> teleport.join.v1.JoinResponse
33, // [33:34] is the sub-list for method output_type
32, // [32:33] is the sub-list for method input_type
32, // [32:32] is the sub-list for extension type_name
32, // [32:32] is the sub-list for extension extendee
0, // [0:32] is the sub-list for field type_name
5, // 7: teleport.join.v1.OIDCInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 8: teleport.join.v1.BoundKeypairInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 9: teleport.join.v1.IAMInit.client_params:type_name -> teleport.join.v1.ClientParams
5, // 10: teleport.join.v1.EC2Init.client_params:type_name -> teleport.join.v1.ClientParams
10, // 11: teleport.join.v1.ChallengeSolution.bound_keypair_challenge_solution:type_name -> teleport.join.v1.BoundKeypairChallengeSolution
12, // 12: teleport.join.v1.ChallengeSolution.bound_keypair_rotation_response:type_name -> teleport.join.v1.BoundKeypairRotationResponse
16, // 13: teleport.join.v1.ChallengeSolution.iam_challenge_solution:type_name -> teleport.join.v1.IAMChallengeSolution
0, // 14: teleport.join.v1.GivingUp.reason:type_name -> teleport.join.v1.GivingUp.Reason
1, // 15: teleport.join.v1.JoinRequest.client_init:type_name -> teleport.join.v1.ClientInit
6, // 16: teleport.join.v1.JoinRequest.token_init:type_name -> teleport.join.v1.TokenInit
8, // 17: teleport.join.v1.JoinRequest.bound_keypair_init:type_name -> teleport.join.v1.BoundKeypairInit
18, // 18: teleport.join.v1.JoinRequest.solution:type_name -> teleport.join.v1.ChallengeSolution
14, // 19: teleport.join.v1.JoinRequest.iam_init:type_name -> teleport.join.v1.IAMInit
19, // 20: teleport.join.v1.JoinRequest.giving_up:type_name -> teleport.join.v1.GivingUp
17, // 21: teleport.join.v1.JoinRequest.ec2_init:type_name -> teleport.join.v1.EC2Init
7, // 22: teleport.join.v1.JoinRequest.oidc_init:type_name -> teleport.join.v1.OIDCInit
9, // 23: teleport.join.v1.Challenge.bound_keypair_challenge:type_name -> teleport.join.v1.BoundKeypairChallenge
11, // 24: teleport.join.v1.Challenge.bound_keypair_rotation_request:type_name -> teleport.join.v1.BoundKeypairRotationRequest
15, // 25: teleport.join.v1.Challenge.iam_challenge:type_name -> teleport.join.v1.IAMChallenge
25, // 26: teleport.join.v1.Result.host_result:type_name -> teleport.join.v1.HostResult
26, // 27: teleport.join.v1.Result.bot_result:type_name -> teleport.join.v1.BotResult
24, // 28: teleport.join.v1.HostResult.certificates:type_name -> teleport.join.v1.Certificates
24, // 29: teleport.join.v1.BotResult.certificates:type_name -> teleport.join.v1.Certificates
13, // 30: teleport.join.v1.BotResult.bound_keypair_result:type_name -> teleport.join.v1.BoundKeypairResult
21, // 31: teleport.join.v1.JoinResponse.init:type_name -> teleport.join.v1.ServerInit
22, // 32: teleport.join.v1.JoinResponse.challenge:type_name -> teleport.join.v1.Challenge
23, // 33: teleport.join.v1.JoinResponse.result:type_name -> teleport.join.v1.Result
20, // 34: teleport.join.v1.JoinService.Join:input_type -> teleport.join.v1.JoinRequest
27, // 35: teleport.join.v1.JoinService.Join:output_type -> teleport.join.v1.JoinResponse
35, // [35:36] is the sub-list for method output_type
34, // [34:35] is the sub-list for method input_type
34, // [34:34] is the sub-list for extension type_name
34, // [34:34] is the sub-list for extension extendee
0, // [0:34] is the sub-list for field type_name
}
func init() { file_teleport_join_v1_joinservice_proto_init() }
@@ -2220,12 +2304,12 @@ func file_teleport_join_v1_joinservice_proto_init() {
(*ClientParams_HostParams)(nil),
(*ClientParams_BotParams)(nil),
}
file_teleport_join_v1_joinservice_proto_msgTypes[16].OneofWrappers = []any{
file_teleport_join_v1_joinservice_proto_msgTypes[17].OneofWrappers = []any{
(*ChallengeSolution_BoundKeypairChallengeSolution)(nil),
(*ChallengeSolution_BoundKeypairRotationResponse)(nil),
(*ChallengeSolution_IamChallengeSolution)(nil),
}
file_teleport_join_v1_joinservice_proto_msgTypes[18].OneofWrappers = []any{
file_teleport_join_v1_joinservice_proto_msgTypes[19].OneofWrappers = []any{
(*JoinRequest_ClientInit)(nil),
(*JoinRequest_TokenInit)(nil),
(*JoinRequest_BoundKeypairInit)(nil),
@@ -2233,18 +2317,19 @@ func file_teleport_join_v1_joinservice_proto_init() {
(*JoinRequest_IamInit)(nil),
(*JoinRequest_GivingUp)(nil),
(*JoinRequest_Ec2Init)(nil),
(*JoinRequest_OidcInit)(nil),
}
file_teleport_join_v1_joinservice_proto_msgTypes[20].OneofWrappers = []any{
file_teleport_join_v1_joinservice_proto_msgTypes[21].OneofWrappers = []any{
(*Challenge_BoundKeypairChallenge)(nil),
(*Challenge_BoundKeypairRotationRequest)(nil),
(*Challenge_IamChallenge)(nil),
}
file_teleport_join_v1_joinservice_proto_msgTypes[21].OneofWrappers = []any{
file_teleport_join_v1_joinservice_proto_msgTypes[22].OneofWrappers = []any{
(*Result_HostResult)(nil),
(*Result_BotResult)(nil),
}
file_teleport_join_v1_joinservice_proto_msgTypes[24].OneofWrappers = []any{}
file_teleport_join_v1_joinservice_proto_msgTypes[25].OneofWrappers = []any{
file_teleport_join_v1_joinservice_proto_msgTypes[25].OneofWrappers = []any{}
file_teleport_join_v1_joinservice_proto_msgTypes[26].OneofWrappers = []any{
(*JoinResponse_Init)(nil),
(*JoinResponse_Challenge)(nil),
(*JoinResponse_Result)(nil),
@@ -2255,7 +2340,7 @@ func file_teleport_join_v1_joinservice_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_join_v1_joinservice_proto_rawDesc), len(file_teleport_join_v1_joinservice_proto_rawDesc)),
NumEnums: 1,
NumMessages: 27,
NumMessages: 28,
NumExtensions: 0,
NumServices: 1,
},
@@ -66,7 +66,9 @@ type JoinAttrs struct {
// Attributes that are specific to the Oracle (`oracle`) join method.
Oracle *JoinAttrsOracle `protobuf:"bytes,13,opt,name=oracle,proto3" json:"oracle,omitempty"`
// Attributes that are specific to the Azure Devops (`azure_devops`) join method.
AzureDevops *JoinAttrsAzureDevops `protobuf:"bytes,14,opt,name=azure_devops,json=azureDevops,proto3" json:"azure_devops,omitempty"`
AzureDevops *JoinAttrsAzureDevops `protobuf:"bytes,14,opt,name=azure_devops,json=azureDevops,proto3" json:"azure_devops,omitempty"`
// Attributes that are specific to the Env0 (`env0`) join method.
Env0 *JoinAttrsEnv0 `protobuf:"bytes,15,opt,name=env0,proto3" json:"env0,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -199,6 +201,13 @@ func (x *JoinAttrs) GetAzureDevops() *JoinAttrsAzureDevops {
return nil
}
func (x *JoinAttrs) GetEnv0() *JoinAttrsEnv0 {
if x != nil {
return x.Env0
}
return nil
}
// The collection of attributes that result from the join process but are not
// specific to any particular join method.
type JoinAttrsMeta struct {
@@ -1717,11 +1726,176 @@ func (x *JoinAttrsAzureDevopsPipeline) GetRunId() string {
return ""
}
// Attributes that are specific to the Env0 (`env0`) join method.
type JoinAttrsEnv0 struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The `sub` claim of an Env0 OIDC token.
Sub string `protobuf:"bytes,1,opt,name=sub,proto3" json:"sub,omitempty"`
// The unique organization identifier, corresponding to `organizationId` in an
// Env0 OIDC token.
OrganizationId string `protobuf:"bytes,2,opt,name=organization_id,json=organizationId,proto3" json:"organization_id,omitempty"`
// The unique project identifier, corresponding to `projectId` in an Env0 OIDC
// token.
ProjectId string `protobuf:"bytes,3,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"`
// The name of the project under which the job was run corresponding to
// `projectName` in an Env0 OIDC token.
ProjectName string `protobuf:"bytes,4,opt,name=project_name,json=projectName,proto3" json:"project_name,omitempty"`
// The unique identifier of the Env0 template, corresponding to `templateId`
// in an Env0 OIDC token.
TemplateId string `protobuf:"bytes,5,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"`
// The name of the Env0 template, corresponding to `templateName` in an Env0
// OIDC token.
TemplateName string `protobuf:"bytes,6,opt,name=template_name,json=templateName,proto3" json:"template_name,omitempty"`
// The unique identifier of the Env0 environment, corresponding to
// `environmentId` in an Env0 OIDC token.
EnvironmentId string `protobuf:"bytes,7,opt,name=environment_id,json=environmentId,proto3" json:"environment_id,omitempty"`
// The name of the Env0 environment, corresponding to `environmentName` in an
// Env0 OIDC token.
EnvironmentName string `protobuf:"bytes,8,opt,name=environment_name,json=environmentName,proto3" json:"environment_name,omitempty"`
// The name of the Env0 workspace, corresponding to `workspaceName` in an Env0
// OIDC token.
WorkspaceName string `protobuf:"bytes,9,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"`
// A unique ID for this deployment, corresponding to `deploymentLogId` in an
// Env0 OIDC token.
DeploymentLogId string `protobuf:"bytes,10,opt,name=deployment_log_id,json=deploymentLogId,proto3" json:"deployment_log_id,omitempty"`
// The env0 deployment type, such as "deploy", "destroy", etc. Corresponds to
// `deploymentType` in an Env0 OIDC token.
DeploymentType string `protobuf:"bytes,11,opt,name=deployment_type,json=deploymentType,proto3" json:"deployment_type,omitempty"`
// The email of the person that triggered the deployment, corresponding to
// `deployerEmail` in an Env0 OIDC token.
DeployerEmail string `protobuf:"bytes,12,opt,name=deployer_email,json=deployerEmail,proto3" json:"deployer_email,omitempty"`
// A custom tag value corresponding to `env0Tag` when `ENV0_OIDC_TAG` is set.
Env0Tag string `protobuf:"bytes,13,opt,name=env0_tag,json=env0Tag,proto3" json:"env0_tag,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *JoinAttrsEnv0) Reset() {
*x = JoinAttrsEnv0{}
mi := &file_teleport_workloadidentity_v1_join_attrs_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *JoinAttrsEnv0) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*JoinAttrsEnv0) ProtoMessage() {}
func (x *JoinAttrsEnv0) ProtoReflect() protoreflect.Message {
mi := &file_teleport_workloadidentity_v1_join_attrs_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use JoinAttrsEnv0.ProtoReflect.Descriptor instead.
func (*JoinAttrsEnv0) Descriptor() ([]byte, []int) {
return file_teleport_workloadidentity_v1_join_attrs_proto_rawDescGZIP(), []int{19}
}
func (x *JoinAttrsEnv0) GetSub() string {
if x != nil {
return x.Sub
}
return ""
}
func (x *JoinAttrsEnv0) GetOrganizationId() string {
if x != nil {
return x.OrganizationId
}
return ""
}
func (x *JoinAttrsEnv0) GetProjectId() string {
if x != nil {
return x.ProjectId
}
return ""
}
func (x *JoinAttrsEnv0) GetProjectName() string {
if x != nil {
return x.ProjectName
}
return ""
}
func (x *JoinAttrsEnv0) GetTemplateId() string {
if x != nil {
return x.TemplateId
}
return ""
}
func (x *JoinAttrsEnv0) GetTemplateName() string {
if x != nil {
return x.TemplateName
}
return ""
}
func (x *JoinAttrsEnv0) GetEnvironmentId() string {
if x != nil {
return x.EnvironmentId
}
return ""
}
func (x *JoinAttrsEnv0) GetEnvironmentName() string {
if x != nil {
return x.EnvironmentName
}
return ""
}
func (x *JoinAttrsEnv0) GetWorkspaceName() string {
if x != nil {
return x.WorkspaceName
}
return ""
}
func (x *JoinAttrsEnv0) GetDeploymentLogId() string {
if x != nil {
return x.DeploymentLogId
}
return ""
}
func (x *JoinAttrsEnv0) GetDeploymentType() string {
if x != nil {
return x.DeploymentType
}
return ""
}
func (x *JoinAttrsEnv0) GetDeployerEmail() string {
if x != nil {
return x.DeployerEmail
}
return ""
}
func (x *JoinAttrsEnv0) GetEnv0Tag() string {
if x != nil {
return x.Env0Tag
}
return ""
}
var File_teleport_workloadidentity_v1_join_attrs_proto protoreflect.FileDescriptor
const file_teleport_workloadidentity_v1_join_attrs_proto_rawDesc = "" +
"\n" +
"-teleport/workloadidentity/v1/join_attrs.proto\x12\x1cteleport.workloadidentity.v1\"\x99\b\n" +
"-teleport/workloadidentity/v1/join_attrs.proto\x12\x1cteleport.workloadidentity.v1\"\xda\b\n" +
"\tJoinAttrs\x12?\n" +
"\x04meta\x18\x01 \x01(\v2+.teleport.workloadidentity.v1.JoinAttrsMetaR\x04meta\x12E\n" +
"\x06gitlab\x18\x02 \x01(\v2-.teleport.workloadidentity.v1.JoinAttrsGitLabR\x06gitlab\x12E\n" +
@@ -1739,7 +1913,8 @@ const file_teleport_workloadidentity_v1_join_attrs_proto_rawDesc = "" +
"kubernetes\x18\f \x01(\v21.teleport.workloadidentity.v1.JoinAttrsKubernetesR\n" +
"kubernetes\x12E\n" +
"\x06oracle\x18\r \x01(\v2-.teleport.workloadidentity.v1.JoinAttrsOracleR\x06oracle\x12U\n" +
"\fazure_devops\x18\x0e \x01(\v22.teleport.workloadidentity.v1.JoinAttrsAzureDevopsR\vazureDevops\"X\n" +
"\fazure_devops\x18\x0e \x01(\v22.teleport.workloadidentity.v1.JoinAttrsAzureDevopsR\vazureDevops\x12?\n" +
"\x04env0\x18\x0f \x01(\v2+.teleport.workloadidentity.v1.JoinAttrsEnv0R\x04env0\"X\n" +
"\rJoinAttrsMeta\x12&\n" +
"\x0fjoin_token_name\x18\x01 \x01(\tR\rjoinTokenName\x12\x1f\n" +
"\vjoin_method\x18\x02 \x01(\tR\n" +
@@ -1862,7 +2037,24 @@ const file_teleport_workloadidentity_v1_join_attrs_proto_rawDesc = "" +
"\x12repository_version\x18\t \x01(\tR\x11repositoryVersion\x12%\n" +
"\x0erepository_ref\x18\n" +
" \x01(\tR\rrepositoryRef\x12\x15\n" +
"\x06run_id\x18\v \x01(\tR\x05runIdBdZbgithub.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1;workloadidentityv1b\x06proto3"
"\x06run_id\x18\v \x01(\tR\x05runId\"\xe2\x03\n" +
"\rJoinAttrsEnv0\x12\x10\n" +
"\x03sub\x18\x01 \x01(\tR\x03sub\x12'\n" +
"\x0forganization_id\x18\x02 \x01(\tR\x0eorganizationId\x12\x1d\n" +
"\n" +
"project_id\x18\x03 \x01(\tR\tprojectId\x12!\n" +
"\fproject_name\x18\x04 \x01(\tR\vprojectName\x12\x1f\n" +
"\vtemplate_id\x18\x05 \x01(\tR\n" +
"templateId\x12#\n" +
"\rtemplate_name\x18\x06 \x01(\tR\ftemplateName\x12%\n" +
"\x0eenvironment_id\x18\a \x01(\tR\renvironmentId\x12)\n" +
"\x10environment_name\x18\b \x01(\tR\x0fenvironmentName\x12%\n" +
"\x0eworkspace_name\x18\t \x01(\tR\rworkspaceName\x12*\n" +
"\x11deployment_log_id\x18\n" +
" \x01(\tR\x0fdeploymentLogId\x12'\n" +
"\x0fdeployment_type\x18\v \x01(\tR\x0edeploymentType\x12%\n" +
"\x0edeployer_email\x18\f \x01(\tR\rdeployerEmail\x12\x19\n" +
"\benv0_tag\x18\r \x01(\tR\aenv0TagBdZbgithub.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1;workloadidentityv1b\x06proto3"
var (
file_teleport_workloadidentity_v1_join_attrs_proto_rawDescOnce sync.Once
@@ -1876,7 +2068,7 @@ func file_teleport_workloadidentity_v1_join_attrs_proto_rawDescGZIP() []byte {
return file_teleport_workloadidentity_v1_join_attrs_proto_rawDescData
}
var file_teleport_workloadidentity_v1_join_attrs_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
var file_teleport_workloadidentity_v1_join_attrs_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_teleport_workloadidentity_v1_join_attrs_proto_goTypes = []any{
(*JoinAttrs)(nil), // 0: teleport.workloadidentity.v1.JoinAttrs
(*JoinAttrsMeta)(nil), // 1: teleport.workloadidentity.v1.JoinAttrsMeta
@@ -1897,6 +2089,7 @@ var file_teleport_workloadidentity_v1_join_attrs_proto_goTypes = []any{
(*JoinAttrsOracle)(nil), // 16: teleport.workloadidentity.v1.JoinAttrsOracle
(*JoinAttrsAzureDevops)(nil), // 17: teleport.workloadidentity.v1.JoinAttrsAzureDevops
(*JoinAttrsAzureDevopsPipeline)(nil), // 18: teleport.workloadidentity.v1.JoinAttrsAzureDevopsPipeline
(*JoinAttrsEnv0)(nil), // 19: teleport.workloadidentity.v1.JoinAttrsEnv0
}
var file_teleport_workloadidentity_v1_join_attrs_proto_depIdxs = []int32{
1, // 0: teleport.workloadidentity.v1.JoinAttrs.meta:type_name -> teleport.workloadidentity.v1.JoinAttrsMeta
@@ -1913,15 +2106,16 @@ var file_teleport_workloadidentity_v1_join_attrs_proto_depIdxs = []int32{
15, // 11: teleport.workloadidentity.v1.JoinAttrs.kubernetes:type_name -> teleport.workloadidentity.v1.JoinAttrsKubernetes
16, // 12: teleport.workloadidentity.v1.JoinAttrs.oracle:type_name -> teleport.workloadidentity.v1.JoinAttrsOracle
17, // 13: teleport.workloadidentity.v1.JoinAttrs.azure_devops:type_name -> teleport.workloadidentity.v1.JoinAttrsAzureDevops
11, // 14: teleport.workloadidentity.v1.JoinAttrsGCP.gce:type_name -> teleport.workloadidentity.v1.JoinAttrsGCPGCE
14, // 15: teleport.workloadidentity.v1.JoinAttrsKubernetes.service_account:type_name -> teleport.workloadidentity.v1.JoinAttrsKubernetesServiceAccount
13, // 16: teleport.workloadidentity.v1.JoinAttrsKubernetes.pod:type_name -> teleport.workloadidentity.v1.JoinAttrsKubernetesPod
18, // 17: teleport.workloadidentity.v1.JoinAttrsAzureDevops.pipeline:type_name -> teleport.workloadidentity.v1.JoinAttrsAzureDevopsPipeline
18, // [18:18] is the sub-list for method output_type
18, // [18:18] is the sub-list for method input_type
18, // [18:18] is the sub-list for extension type_name
18, // [18:18] is the sub-list for extension extendee
0, // [0:18] is the sub-list for field type_name
19, // 14: teleport.workloadidentity.v1.JoinAttrs.env0:type_name -> teleport.workloadidentity.v1.JoinAttrsEnv0
11, // 15: teleport.workloadidentity.v1.JoinAttrsGCP.gce:type_name -> teleport.workloadidentity.v1.JoinAttrsGCPGCE
14, // 16: teleport.workloadidentity.v1.JoinAttrsKubernetes.service_account:type_name -> teleport.workloadidentity.v1.JoinAttrsKubernetesServiceAccount
13, // 17: teleport.workloadidentity.v1.JoinAttrsKubernetes.pod:type_name -> teleport.workloadidentity.v1.JoinAttrsKubernetesPod
18, // 18: teleport.workloadidentity.v1.JoinAttrsAzureDevops.pipeline:type_name -> teleport.workloadidentity.v1.JoinAttrsAzureDevopsPipeline
19, // [19:19] is the sub-list for method output_type
19, // [19:19] is the sub-list for method input_type
19, // [19:19] is the sub-list for extension type_name
19, // [19:19] is the sub-list for extension extendee
0, // [0:19] is the sub-list for field type_name
}
func init() { file_teleport_workloadidentity_v1_join_attrs_proto_init() }
@@ -1935,7 +2129,7 @@ func file_teleport_workloadidentity_v1_join_attrs_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_workloadidentity_v1_join_attrs_proto_rawDesc), len(file_teleport_workloadidentity_v1_join_attrs_proto_rawDesc)),
NumEnums: 0,
NumMessages: 19,
NumMessages: 20,
NumExtensions: 0,
NumServices: 0,
},
@@ -107,6 +107,20 @@ message TokenInit {
ClientParams client_params = 1;
}
// OIDCInit holds the OIDC identity token used for all OIDC-based join methods.
//
// The join flow for all OIDC-based join methods is:
// 1. client->server: ClientInit
// 2. server->client: ServerInit
// 3. client->server: OIDCInit
// 4. server->client: Result
message OIDCInit {
// ClientParams holds parameters for the specific type of client trying to join.
ClientParams client_params = 1;
// IdToken is the OIDC identity token.
bytes id_token = 2;
}
// BoundKeypairInit is sent from the client in response to the ServerInit
// message for the bound keypair join method.
// The server is expected to respond with a BoundKeypairChallenge.
@@ -280,6 +294,7 @@ message JoinRequest {
IAMInit iam_init = 5;
GivingUp giving_up = 6;
EC2Init ec2_init = 7;
OIDCInit oidc_init = 8;
}
}
@@ -1555,6 +1555,8 @@ message ProvisionTokenSpecV2 {
ProvisionTokenSpecV2BoundKeypair BoundKeypair = 19 [(gogoproto.jsontag) = "bound_keypair,omitempty"];
// AzureDevops allows the configuration of options specific to the "azure_devops" join method.
ProvisionTokenSpecV2AzureDevops AzureDevops = 20 [(gogoproto.jsontag) = "azure_devops,omitempty"];
// Env0 allows the configuration of options specific to the "env0" join method.
ProvisionTokenSpecV2Env0 Env0 = 21 [(gogoproto.jsontag) = "env0,omitempty"];
}
// ProvisionTokenSpecV2AzureDevops contains the Azure Devops-specific
@@ -2044,6 +2046,51 @@ message ProvisionTokenSpecV2Oracle {
repeated Rule Allow = 1 [(gogoproto.jsontag) = "allow,omitempty"];
}
// ProvisionTokenSpecV2Env0 contains env0-specific parts of the
// ProvisionTokenSpecV2.
message ProvisionTokenSpecV2Env0 {
// Rule is a set of properties the env0 environment might have to be allowed
// to use this provision token.
message Rule {
// OrganizationID is the unique organization identifier, corresponding to
// `organizationId` in an Env0 OIDC token.
string OrganizationID = 1 [(gogoproto.jsontag) = "organization_id,omitempty"];
// ProjectID is a unique project identifier, corresponding to `projectId` in
// an Env0 OIDC token.
string ProjectID = 2 [(gogoproto.jsontag) = "project_id,omitempty"];
// ProjectName is the name of the project under which the job was run
// corresponding to `projectName` in an Env0 OIDC token.
string ProjectName = 3 [(gogoproto.jsontag) = "project_name,omitempty"];
// TemplateID is the unique identifier of the Env0 template, corresponding
// to `templateId` in an Env0 OIDC token.
string TemplateID = 4 [(gogoproto.jsontag) = "template_id,omitempty"];
// TemplateName is the name of the Env0 template, corresponding to
// `templateName` in an Env0 OIDC token.
string TemplateName = 5 [(gogoproto.jsontag) = "template_name,omitempty"];
// EnvironmentID is the unique identifier of the Env0 environment,
// corresponding to `environmentId` in an Env0 OIDC token.
string EnvironmentID = 6 [(gogoproto.jsontag) = "environment_id,omitempty"];
// EnvironmentName is the name of the Env0 environment, corresponding to
// `environmentName` in an Env0 OIDC token.
string EnvironmentName = 7 [(gogoproto.jsontag) = "environment_name,omitempty"];
// WorkspaceName is the name of the Env0 workspace, corresponding to
// `workspaceName` in an Env0 OIDC token.
string WorkspaceName = 8 [(gogoproto.jsontag) = "workspace_name,omitempty"];
// DeploymentType is the env0 deployment type, such as "deploy", "destroy",
// etc. Corresponds to `deploymentType` in an Env0 OIDC token.
string DeploymentType = 9 [(gogoproto.jsontag) = "deployment_type,omitempty"];
// DeployerEmail is the email of the person that triggered the deployment,
// corresponding to `deployerEmail` in an Env0 OIDC token.
string DeployerEmail = 10 [(gogoproto.jsontag) = "deployer_email,omitempty"];
// Env0Tag is a custom tag value corresponding to `env0Tag` when
// `ENV0_OIDC_TAG` is set.
string Env0Tag = 11 [(gogoproto.jsontag) = "env0_tag,omitempty"];
}
// Allow is a list of Rules, jobs using this token must match at least one
// allow rule to use this token.
repeated Rule Allow = 1 [(gogoproto.jsontag) = "allow,omitempty"];
}
// ProvisionTokenSpecV2BoundKeypair contains configuration for bound_keypair
// type join tokens.
message ProvisionTokenSpecV2BoundKeypair {
@@ -49,6 +49,8 @@ message JoinAttrs {
JoinAttrsOracle oracle = 13;
// Attributes that are specific to the Azure Devops (`azure_devops`) join method.
JoinAttrsAzureDevops azure_devops = 14;
// Attributes that are specific to the Env0 (`env0`) join method.
JoinAttrsEnv0 env0 = 15;
}
// The collection of attributes that result from the join process but are not
@@ -358,3 +360,44 @@ message JoinAttrsAzureDevopsPipeline {
// The ID of the run that is being executed.
string run_id = 11;
}
// Attributes that are specific to the Env0 (`env0`) join method.
message JoinAttrsEnv0 {
// The `sub` claim of an Env0 OIDC token.
string sub = 1;
// The unique organization identifier, corresponding to `organizationId` in an
// Env0 OIDC token.
string organization_id = 2;
// The unique project identifier, corresponding to `projectId` in an Env0 OIDC
// token.
string project_id = 3;
// The name of the project under which the job was run corresponding to
// `projectName` in an Env0 OIDC token.
string project_name = 4;
// The unique identifier of the Env0 template, corresponding to `templateId`
// in an Env0 OIDC token.
string template_id = 5;
// The name of the Env0 template, corresponding to `templateName` in an Env0
// OIDC token.
string template_name = 6;
// The unique identifier of the Env0 environment, corresponding to
// `environmentId` in an Env0 OIDC token.
string environment_id = 7;
// The name of the Env0 environment, corresponding to `environmentName` in an
// Env0 OIDC token.
string environment_name = 8;
// The name of the Env0 workspace, corresponding to `workspaceName` in an Env0
// OIDC token.
string workspace_name = 9;
// A unique ID for this deployment, corresponding to `deploymentLogId` in an
// Env0 OIDC token.
string deployment_log_id = 10;
// The env0 deployment type, such as "deploy", "destroy", etc. Corresponds to
// `deploymentType` in an Env0 OIDC token.
string deployment_type = 11;
// The email of the person that triggered the deployment, corresponding to
// `deployerEmail` in an Env0 OIDC token.
string deployer_email = 12;
// A custom tag value corresponding to `env0Tag` when `ENV0_OIDC_TAG` is set.
string env0_tag = 13;
}
+29
View File
@@ -87,6 +87,8 @@ const (
// JoinMethodBoundKeypair indicates the node will join using the Bound
// Keypair join method. See lib/boundkeypair for more.
JoinMethodBoundKeypair JoinMethod = "bound_keypair"
// JoinMethodEnv0 indicates the node will join using the env0 join method.
JoinMethodEnv0 JoinMethod = "env0"
)
var JoinMethods = []JoinMethod{
@@ -106,6 +108,7 @@ var JoinMethods = []JoinMethod{
JoinMethodTerraformCloud,
JoinMethodOracle,
JoinMethodBoundKeypair,
JoinMethodEnv0,
}
func ValidateJoinMethod(method JoinMethod) error {
@@ -450,6 +453,14 @@ func (p *ProvisionTokenV2) CheckAndSetDefaults() error {
if err := p.Spec.BoundKeypair.checkAndSetDefaults(); err != nil {
return trace.Wrap(err, "spec.bound_keypair: failed validation")
}
case JoinMethodEnv0:
if p.Spec.Env0 == nil {
p.Spec.Env0 = &ProvisionTokenSpecV2Env0{}
}
if err := p.Spec.Env0.checkAndSetDefaults(); err != nil {
return trace.Wrap(err, "spec.env0: failed validation")
}
default:
return trace.BadParameter("unknown join method %q", p.Spec.JoinMethod)
}
@@ -1073,3 +1084,21 @@ func (a *ProvisionTokenSpecV2BoundKeypair) checkAndSetDefaults() error {
return nil
}
func (a *ProvisionTokenSpecV2Env0) checkAndSetDefaults() error {
if len(a.Allow) == 0 {
return trace.BadParameter("the %q join method requires at least one token allow rule", JoinMethodEnv0)
}
for i, allowRule := range a.Allow {
if allowRule.OrganizationID == "" {
return trace.BadParameter("allow[%d]: organization_id must be set", i)
}
if allowRule.ProjectID == "" && allowRule.ProjectName == "" {
return trace.BadParameter("allow[%d]: at least one of ['project_id', 'project_name'] must be set", i)
}
}
return nil
}
+150
View File
@@ -1496,6 +1496,156 @@ func TestProvisionTokenV2_CheckAndSetDefaults(t *testing.T) {
},
wantErr: false,
},
{
desc: "env0 success",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "organization-id",
ProjectID: "project-id",
ProjectName: "project-name",
TemplateID: "template-id",
TemplateName: "template-name",
EnvironmentID: "environment-id",
EnvironmentName: "environment-name",
WorkspaceName: "workspace-name",
DeploymentType: "deployment-type",
DeployerEmail: "deployer-email",
Env0Tag: "custom-tag",
},
},
},
},
},
expected: &ProvisionTokenV2{
Kind: "token",
Version: "v2",
Metadata: Metadata{
Name: "test",
Namespace: "default",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "organization-id",
ProjectID: "project-id",
ProjectName: "project-name",
TemplateID: "template-id",
TemplateName: "template-name",
EnvironmentID: "environment-id",
EnvironmentName: "environment-name",
WorkspaceName: "workspace-name",
DeploymentType: "deployment-type",
DeployerEmail: "deployer-email",
Env0Tag: "custom-tag",
},
},
},
},
},
wantErr: false,
},
{
desc: "env0 multiple rules - success",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "organization-id",
ProjectID: "project-id",
},
{
OrganizationID: "organization-id",
ProjectName: "project-name",
},
},
},
},
},
expected: &ProvisionTokenV2{
Kind: "token",
Version: "v2",
Metadata: Metadata{
Name: "test",
Namespace: "default",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "organization-id",
ProjectID: "project-id",
},
{
OrganizationID: "organization-id",
ProjectName: "project-name",
},
},
},
},
},
wantErr: false,
},
{
desc: "env0 missing organization",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
ProjectName: "test",
TemplateName: "test",
},
},
},
},
},
wantErr: true,
},
{
desc: "env0 missing project",
token: &ProvisionTokenV2{
Metadata: Metadata{
Name: "test",
},
Spec: ProvisionTokenSpecV2{
Roles: []SystemRole{RoleNode},
JoinMethod: JoinMethodEnv0,
Env0: &ProvisionTokenSpecV2Env0{
Allow: []*ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "test",
TemplateName: "test",
},
},
},
},
},
wantErr: true,
},
}
for _, tc := range testcases {
+3742 -2846
View File
File diff suppressed because it is too large Load Diff
@@ -38,6 +38,7 @@ resource, which you can apply after installing the Teleport Kubernetes operator.
|bot_name|string|BotName is the name of the bot this token grants access to, if any|
|bound_keypair|[object](#specbound_keypair)|BoundKeypair allows the configuration of options specific to the "bound_keypair" join method.|
|circleci|[object](#speccircleci)|CircleCI allows the configuration of options specific to the "circleci" join method.|
|env0|[object](#specenv0)|Env0 allows the configuration of options specific to the "env0" join method.|
|gcp|[object](#specgcp)|GCP allows the configuration of options specific to the "gcp" join method.|
|github|[object](#specgithub)|GitHub allows the configuration of options specific to the "github" join method.|
|gitlab|[object](#specgitlab)|GitLab allows the configuration of options specific to the "gitlab" join method.|
@@ -147,6 +148,28 @@ resource, which you can apply after installing the Teleport Kubernetes operator.
|context_id|string||
|project_id|string||
### spec.env0
|Field|Type|Description|
|---|---|---|
|allow|[][object](#specenv0allow-items)|Allow is a list of Rules, jobs using this token must match at least one allow rule to use this token.|
### spec.env0.allow items
|Field|Type|Description|
|---|---|---|
|deployer_email|string||
|deployment_type|string||
|env0_tag|string||
|environment_id|string||
|environment_name|string||
|organization_id|string||
|project_id|string||
|project_name|string||
|template_id|string||
|template_name|string||
|workspace_name|string||
### spec.gcp
|Field|Type|Description|
@@ -48,6 +48,7 @@ Optional:
- `bot_name` (String) BotName is the name of the bot this token grants access to, if any
- `bound_keypair` (Attributes) BoundKeypair allows the configuration of options specific to the "bound_keypair" join method. (see [below for nested schema](#nested-schema-for-specbound_keypair))
- `circleci` (Attributes) CircleCI allows the configuration of options specific to the "circleci" join method. (see [below for nested schema](#nested-schema-for-speccircleci))
- `env0` (Attributes) Env0 allows the configuration of options specific to the "env0" join method. (see [below for nested schema](#nested-schema-for-specenv0))
- `gcp` (Attributes) GCP allows the configuration of options specific to the "gcp" join method. (see [below for nested schema](#nested-schema-for-specgcp))
- `github` (Attributes) GitHub allows the configuration of options specific to the "github" join method. (see [below for nested schema](#nested-schema-for-specgithub))
- `gitlab` (Attributes) GitLab allows the configuration of options specific to the "gitlab" join method. (see [below for nested schema](#nested-schema-for-specgitlab))
@@ -168,6 +169,30 @@ Optional:
### Nested Schema for `spec.env0`
Optional:
- `allow` (Attributes List) Allow is a list of Rules, jobs using this token must match at least one allow rule to use this token. (see [below for nested schema](#nested-schema-for-specenv0allow))
### Nested Schema for `spec.env0.allow`
Optional:
- `deployer_email` (String) DeployerEmail is the email of the person that triggered the deployment, corresponding to `deployerEmail` in an Env0 OIDC token.
- `deployment_type` (String) DeploymentType is the env0 deployment type, such as "deploy", "destroy", etc. Corresponds to `deploymentType` in an Env0 OIDC token.
- `env0_tag` (String) Env0Tag is a custom tag value corresponding to `env0Tag` when `ENV0_OIDC_TAG` is set.
- `environment_id` (String) EnvironmentID is the unique identifier of the Env0 environment, corresponding to `environmentId` in an Env0 OIDC token.
- `environment_name` (String) EnvironmentName is the name of the Env0 environment, corresponding to `environmentName` in an Env0 OIDC token.
- `organization_id` (String) OrganizationID is the unique organization identifier, corresponding to `organizationId` in an Env0 OIDC token.
- `project_id` (String) ProjectID is a unique project identifier, corresponding to `projectId` in an Env0 OIDC token.
- `project_name` (String) ProjectName is the name of the project under which the job was run corresponding to `projectName` in an Env0 OIDC token.
- `template_id` (String) TemplateID is the unique identifier of the Env0 template, corresponding to `templateId` in an Env0 OIDC token.
- `template_name` (String) TemplateName is the name of the Env0 template, corresponding to `templateName` in an Env0 OIDC token.
- `workspace_name` (String) WorkspaceName is the name of the Env0 workspace, corresponding to `workspaceName` in an Env0 OIDC token.
### Nested Schema for `spec.gcp`
Optional:
@@ -84,6 +84,7 @@ Optional:
- `bot_name` (String) BotName is the name of the bot this token grants access to, if any
- `bound_keypair` (Attributes) BoundKeypair allows the configuration of options specific to the "bound_keypair" join method. (see [below for nested schema](#nested-schema-for-specbound_keypair))
- `circleci` (Attributes) CircleCI allows the configuration of options specific to the "circleci" join method. (see [below for nested schema](#nested-schema-for-speccircleci))
- `env0` (Attributes) Env0 allows the configuration of options specific to the "env0" join method. (see [below for nested schema](#nested-schema-for-specenv0))
- `gcp` (Attributes) GCP allows the configuration of options specific to the "gcp" join method. (see [below for nested schema](#nested-schema-for-specgcp))
- `github` (Attributes) GitHub allows the configuration of options specific to the "github" join method. (see [below for nested schema](#nested-schema-for-specgithub))
- `gitlab` (Attributes) GitLab allows the configuration of options specific to the "gitlab" join method. (see [below for nested schema](#nested-schema-for-specgitlab))
@@ -204,6 +205,30 @@ Optional:
### Nested Schema for `spec.env0`
Optional:
- `allow` (Attributes List) Allow is a list of Rules, jobs using this token must match at least one allow rule to use this token. (see [below for nested schema](#nested-schema-for-specenv0allow))
### Nested Schema for `spec.env0.allow`
Optional:
- `deployer_email` (String) DeployerEmail is the email of the person that triggered the deployment, corresponding to `deployerEmail` in an Env0 OIDC token.
- `deployment_type` (String) DeploymentType is the env0 deployment type, such as "deploy", "destroy", etc. Corresponds to `deploymentType` in an Env0 OIDC token.
- `env0_tag` (String) Env0Tag is a custom tag value corresponding to `env0Tag` when `ENV0_OIDC_TAG` is set.
- `environment_id` (String) EnvironmentID is the unique identifier of the Env0 environment, corresponding to `environmentId` in an Env0 OIDC token.
- `environment_name` (String) EnvironmentName is the name of the Env0 environment, corresponding to `environmentName` in an Env0 OIDC token.
- `organization_id` (String) OrganizationID is the unique organization identifier, corresponding to `organizationId` in an Env0 OIDC token.
- `project_id` (String) ProjectID is a unique project identifier, corresponding to `projectId` in an Env0 OIDC token.
- `project_name` (String) ProjectName is the name of the project under which the job was run corresponding to `projectName` in an Env0 OIDC token.
- `template_id` (String) TemplateID is the unique identifier of the Env0 template, corresponding to `templateId` in an Env0 OIDC token.
- `template_name` (String) TemplateName is the name of the Env0 template, corresponding to `templateName` in an Env0 OIDC token.
- `workspace_name` (String) WorkspaceName is the name of the Env0 workspace, corresponding to `workspaceName` in an Env0 OIDC token.
### Nested Schema for `spec.gcp`
Optional:
@@ -235,6 +235,42 @@ spec:
organization_id:
type: string
type: object
env0:
description: Env0 allows the configuration of options specific to
the "env0" join method.
nullable: true
properties:
allow:
description: Allow is a list of Rules, jobs using this token must
match at least one allow rule to use this token.
items:
properties:
deployer_email:
type: string
deployment_type:
type: string
env0_tag:
type: string
environment_id:
type: string
environment_name:
type: string
organization_id:
type: string
project_id:
type: string
project_name:
type: string
template_id:
type: string
template_name:
type: string
workspace_name:
type: string
type: object
nullable: true
type: array
type: object
gcp:
description: GCP allows the configuration of options specific to the
"gcp" join method.
@@ -235,6 +235,42 @@ spec:
organization_id:
type: string
type: object
env0:
description: Env0 allows the configuration of options specific to
the "env0" join method.
nullable: true
properties:
allow:
description: Allow is a list of Rules, jobs using this token must
match at least one allow rule to use this token.
items:
properties:
deployer_email:
type: string
deployment_type:
type: string
env0_tag:
type: string
environment_id:
type: string
environment_name:
type: string
organization_id:
type: string
project_id:
type: string
project_name:
type: string
template_id:
type: string
template_name:
type: string
workspace_name:
type: string
type: object
nullable: true
type: array
type: object
gcp:
description: GCP allows the configuration of options specific to the
"gcp" join method.
@@ -1436,6 +1436,71 @@ func GenSchemaProvisionTokenV2(ctx context.Context) (github_com_hashicorp_terraf
Description: "CircleCI allows the configuration of options specific to the \"circleci\" join method.",
Optional: true,
},
"env0": {
Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allow": {
Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{
"deployer_email": {
Description: "DeployerEmail is the email of the person that triggered the deployment, corresponding to `deployerEmail` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"deployment_type": {
Description: "DeploymentType is the env0 deployment type, such as \"deploy\", \"destroy\", etc. Corresponds to `deploymentType` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"env0_tag": {
Description: "Env0Tag is a custom tag value corresponding to `env0Tag` when `ENV0_OIDC_TAG` is set.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"environment_id": {
Description: "EnvironmentID is the unique identifier of the Env0 environment, corresponding to `environmentId` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"environment_name": {
Description: "EnvironmentName is the name of the Env0 environment, corresponding to `environmentName` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"organization_id": {
Description: "OrganizationID is the unique organization identifier, corresponding to `organizationId` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"project_id": {
Description: "ProjectID is a unique project identifier, corresponding to `projectId` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"project_name": {
Description: "ProjectName is the name of the project under which the job was run corresponding to `projectName` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"template_id": {
Description: "TemplateID is the unique identifier of the Env0 template, corresponding to `templateId` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"template_name": {
Description: "TemplateName is the name of the Env0 template, corresponding to `templateName` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
"workspace_name": {
Description: "WorkspaceName is the name of the Env0 workspace, corresponding to `workspaceName` in an Env0 OIDC token.",
Optional: true,
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
},
}),
Description: "Allow is a list of Rules, jobs using this token must match at least one allow rule to use this token.",
Optional: true,
}}),
Description: "Env0 allows the configuration of options specific to the \"env0\" join method.",
Optional: true,
},
"gcp": {
Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allow": {
Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{
@@ -17048,6 +17113,240 @@ func CopyProvisionTokenV2FromTerraform(_ context.Context, tf github_com_hashicor
}
}
}
{
a, ok := tf.Attrs["env0"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0", "github.com/hashicorp/terraform-plugin-framework/types.Object"})
} else {
obj.Env0 = nil
if !v.Null && !v.Unknown {
tf := v
obj.Env0 = &github_com_gravitational_teleport_api_types.ProvisionTokenSpecV2Env0{}
obj := obj.Env0
{
a, ok := tf.Attrs["allow"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow", "github.com/hashicorp/terraform-plugin-framework/types.List"})
} else {
obj.Allow = make([]*github_com_gravitational_teleport_api_types.ProvisionTokenSpecV2Env0_Rule, len(v.Elems))
if !v.Null && !v.Unknown {
for k, a := range v.Elems {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow", "github_com_hashicorp_terraform_plugin_framework_types.Object"})
} else {
var t *github_com_gravitational_teleport_api_types.ProvisionTokenSpecV2Env0_Rule
if !v.Null && !v.Unknown {
tf := v
t = &github_com_gravitational_teleport_api_types.ProvisionTokenSpecV2Env0_Rule{}
obj := t
{
a, ok := tf.Attrs["organization_id"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.OrganizationID"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.OrganizationID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.OrganizationID = t
}
}
}
{
a, ok := tf.Attrs["project_id"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectID"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.ProjectID = t
}
}
}
{
a, ok := tf.Attrs["project_name"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectName"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.ProjectName = t
}
}
}
{
a, ok := tf.Attrs["template_id"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateID"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.TemplateID = t
}
}
}
{
a, ok := tf.Attrs["template_name"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateName"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.TemplateName = t
}
}
}
{
a, ok := tf.Attrs["environment_id"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentID"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.EnvironmentID = t
}
}
}
{
a, ok := tf.Attrs["environment_name"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentName"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.EnvironmentName = t
}
}
}
{
a, ok := tf.Attrs["workspace_name"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.WorkspaceName"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.WorkspaceName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.WorkspaceName = t
}
}
}
{
a, ok := tf.Attrs["deployment_type"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeploymentType"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeploymentType", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.DeploymentType = t
}
}
}
{
a, ok := tf.Attrs["deployer_email"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeployerEmail"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeployerEmail", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.DeployerEmail = t
}
}
}
{
a, ok := tf.Attrs["env0_tag"]
if !ok {
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.Env0Tag"})
} else {
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.Env0Tag", "github.com/hashicorp/terraform-plugin-framework/types.String"})
} else {
var t string
if !v.Null && !v.Unknown {
t = string(v.Value)
}
obj.Env0Tag = t
}
}
}
}
obj.Allow[k] = t
}
}
}
}
}
}
}
}
}
}
}
}
}
@@ -21113,6 +21412,338 @@ func CopyProvisionTokenV2ToTerraform(ctx context.Context, obj *github_com_gravit
}
}
}
{
a, ok := tf.AttrTypes["env0"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0"})
} else {
o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"})
} else {
v, ok := tf.Attrs["env0"].(github_com_hashicorp_terraform_plugin_framework_types.Object)
if !ok {
v = github_com_hashicorp_terraform_plugin_framework_types.Object{
AttrTypes: o.AttrTypes,
Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)),
}
} else {
if v.Attrs == nil {
v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes))
}
}
if obj.Env0 == nil {
v.Null = true
} else {
obj := obj.Env0
tf := &v
{
a, ok := tf.AttrTypes["allow"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow"})
} else {
o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow", "github.com/hashicorp/terraform-plugin-framework/types.ListType"})
} else {
c, ok := tf.Attrs["allow"].(github_com_hashicorp_terraform_plugin_framework_types.List)
if !ok {
c = github_com_hashicorp_terraform_plugin_framework_types.List{
ElemType: o.ElemType,
Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow)),
Null: true,
}
} else {
if c.Elems == nil {
c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow))
}
}
if obj.Allow != nil {
o := o.ElemType.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType)
if len(obj.Allow) != len(c.Elems) {
c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow))
}
for k, a := range obj.Allow {
v, ok := tf.Attrs["allow"].(github_com_hashicorp_terraform_plugin_framework_types.Object)
if !ok {
v = github_com_hashicorp_terraform_plugin_framework_types.Object{
AttrTypes: o.AttrTypes,
Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)),
}
} else {
if v.Attrs == nil {
v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes))
}
}
if a == nil {
v.Null = true
} else {
obj := a
tf := &v
{
t, ok := tf.AttrTypes["organization_id"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.OrganizationID"})
} else {
v, ok := tf.Attrs["organization_id"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.OrganizationID", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.OrganizationID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.OrganizationID) == ""
}
v.Value = string(obj.OrganizationID)
v.Unknown = false
tf.Attrs["organization_id"] = v
}
}
{
t, ok := tf.AttrTypes["project_id"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectID"})
} else {
v, ok := tf.Attrs["project_id"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.ProjectID", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.ProjectID) == ""
}
v.Value = string(obj.ProjectID)
v.Unknown = false
tf.Attrs["project_id"] = v
}
}
{
t, ok := tf.AttrTypes["project_name"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectName"})
} else {
v, ok := tf.Attrs["project_name"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.ProjectName", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.ProjectName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.ProjectName) == ""
}
v.Value = string(obj.ProjectName)
v.Unknown = false
tf.Attrs["project_name"] = v
}
}
{
t, ok := tf.AttrTypes["template_id"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateID"})
} else {
v, ok := tf.Attrs["template_id"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.TemplateID", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.TemplateID) == ""
}
v.Value = string(obj.TemplateID)
v.Unknown = false
tf.Attrs["template_id"] = v
}
}
{
t, ok := tf.AttrTypes["template_name"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateName"})
} else {
v, ok := tf.Attrs["template_name"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.TemplateName", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.TemplateName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.TemplateName) == ""
}
v.Value = string(obj.TemplateName)
v.Unknown = false
tf.Attrs["template_name"] = v
}
}
{
t, ok := tf.AttrTypes["environment_id"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentID"})
} else {
v, ok := tf.Attrs["environment_id"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentID", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentID", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.EnvironmentID) == ""
}
v.Value = string(obj.EnvironmentID)
v.Unknown = false
tf.Attrs["environment_id"] = v
}
}
{
t, ok := tf.AttrTypes["environment_name"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentName"})
} else {
v, ok := tf.Attrs["environment_name"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentName", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.EnvironmentName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.EnvironmentName) == ""
}
v.Value = string(obj.EnvironmentName)
v.Unknown = false
tf.Attrs["environment_name"] = v
}
}
{
t, ok := tf.AttrTypes["workspace_name"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.WorkspaceName"})
} else {
v, ok := tf.Attrs["workspace_name"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.WorkspaceName", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.WorkspaceName", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.WorkspaceName) == ""
}
v.Value = string(obj.WorkspaceName)
v.Unknown = false
tf.Attrs["workspace_name"] = v
}
}
{
t, ok := tf.AttrTypes["deployment_type"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeploymentType"})
} else {
v, ok := tf.Attrs["deployment_type"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.DeploymentType", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeploymentType", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.DeploymentType) == ""
}
v.Value = string(obj.DeploymentType)
v.Unknown = false
tf.Attrs["deployment_type"] = v
}
}
{
t, ok := tf.AttrTypes["deployer_email"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeployerEmail"})
} else {
v, ok := tf.Attrs["deployer_email"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.DeployerEmail", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.DeployerEmail", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.DeployerEmail) == ""
}
v.Value = string(obj.DeployerEmail)
v.Unknown = false
tf.Attrs["deployer_email"] = v
}
}
{
t, ok := tf.AttrTypes["env0_tag"]
if !ok {
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.Env0.Allow.Env0Tag"})
} else {
v, ok := tf.Attrs["env0_tag"].(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
if err != nil {
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.Env0.Allow.Env0Tag", err})
}
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
if !ok {
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.Env0.Allow.Env0Tag", "github.com/hashicorp/terraform-plugin-framework/types.String"})
}
v.Null = string(obj.Env0Tag) == ""
}
v.Value = string(obj.Env0Tag)
v.Unknown = false
tf.Attrs["env0_tag"] = v
}
}
}
v.Unknown = false
c.Elems[k] = v
}
if len(obj.Allow) > 0 {
c.Null = false
}
}
c.Unknown = false
tf.Attrs["allow"] = c
}
}
}
}
v.Unknown = false
tf.Attrs["env0"] = v
}
}
}
}
v.Unknown = false
tf.Attrs["spec"] = v
+15
View File
@@ -117,8 +117,10 @@ import (
"github.com/gravitational/teleport/lib/integrations/awsra/createsession"
"github.com/gravitational/teleport/lib/inventory"
iterstream "github.com/gravitational/teleport/lib/itertools/stream"
"github.com/gravitational/teleport/lib/join"
joinboundkeypair "github.com/gravitational/teleport/lib/join/boundkeypair"
"github.com/gravitational/teleport/lib/join/ec2join"
"github.com/gravitational/teleport/lib/join/env0"
kubetoken "github.com/gravitational/teleport/lib/kube/token"
"github.com/gravitational/teleport/lib/limiter"
"github.com/gravitational/teleport/lib/loginrule"
@@ -804,6 +806,15 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (as *Server, err error) {
}
}
if as.env0IDTokenValidator == nil {
validator, err := env0.NewIDTokenValidator()
if err != nil {
return nil, trace.Wrap(err)
}
as.env0IDTokenValidator = validator
}
// Add in a login hook for generating state during user login.
as.ulsGenerator, err = userloginstate.NewGenerator(userloginstate.GeneratorConfig{
Log: as.logger,
@@ -1290,6 +1301,10 @@ type Server struct {
// challenge validators. Used to override the implementation used in tests.
createBoundKeypairValidator joinboundkeypair.CreateBoundKeypairValidator
// env0IDTokenValidator is a helper to validate env0 OIDC tokens. Used to
// override the implementation used in tests.
env0IDTokenValidator join.Env0TokenValidator
// loadAllCAs tells tsh to load the host CAs for all clusters when trying to ssh into a node.
loadAllCAs bool
+35
View File
@@ -0,0 +1,35 @@
/*
* Teleport
* Copyright (C) 2023 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package auth
import (
"github.com/gravitational/teleport/lib/join"
)
// SetEnv0IDTokenValidator sets the validator implementation for env0 OIDC
// tokens, used in tests.
func (a *Server) SetEnv0IDTokenValidator(validator join.Env0TokenValidator) {
a.env0IDTokenValidator = validator
}
// GetEnv0IDTokenValidator returns the validator implementation for env0 OIDC
// tokens.
func (a *Server) GetEnv0IDTokenValidator() join.Env0TokenValidator {
return a.env0IDTokenValidator
}
@@ -50,6 +50,7 @@ var SupportedJoinMethods = []types.JoinMethod{
types.JoinMethodAzure,
types.JoinMethodAzureDevops,
types.JoinMethodCircleCI,
types.JoinMethodEnv0,
types.JoinMethodGCP,
types.JoinMethodGitHub,
types.JoinMethodGitLab,
+131
View File
@@ -0,0 +1,131 @@
/*
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package env0
import (
"github.com/zitadel/oidc/v3/pkg/oidc"
workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1"
)
// IDTokenClaims are the additional custom claims provided by Env0 for their
// issued OIDC tokens. See also:
// https://docs.envzero.com/guides/integrations/oidc-integrations
// Example token claims:
//
// {
// "apiKeyType": "oidc",
// "aud": "https://prod.env0.com",
// "azp": "hoMiq9PdkRh9LUvVpH4wIErWg50VSG1b",
// "deployerEmail": "user@email.com",
// "deploymentLogId": "4224831d-05c4-4548-841d-d61988e179cb",
// "deploymentType": "deploy",
// "environmentId": "50aa6e65-2956-4984-aab3-27af9dcc06dc",
// "environmentName": "teleport-env0-demo",
// "exp": 1761193071,
// "gty": "password",
// "https://aws.amazon.com/tags": {
// "principal_tags": {
// "deployerEmail": ["user@email.com"],
// "deploymentType": ["deploy"],
// "environmentId": ["50aa6e65-2956-4984-aab3-27af9dcc06dc"],
// "organizationId": ["948de0c4-94d6-4ad6-8e56-1374353e9a38"],
// "projectId": ["df15f983-808a-49c7-bc91-910cb10411ec"],
// "templateId": ["00d81864-757c-4449-a91c-cf6bee07e44a"]
// }
// },
// "https://env0.com/apiKeyType": "oidc",
// "https://env0.com/deployerEmail": "user@email.com",
// "https://env0.com/deploymentLogId": "4224831d-05c4-4548-841d-d61988e179cb",
// "https://env0.com/deploymentType": "deploy",
// "https://env0.com/environmentId": "50aa6e65-2956-4984-aab3-27af9dcc06dc",
// "https://env0.com/environmentName": "teleport-env0-demo",
// "https://env0.com/organization": "948de0c4-94d6-4ad6-8e56-1374353e9a38",
// "https://env0.com/organizationId": "948de0c4-94d6-4ad6-8e56-1374353e9a38",
// "https://env0.com/projectId": "df15f983-808a-49c7-bc91-910cb10411ec",
// "https://env0.com/projectName": "My First Project",
// "https://env0.com/templateId": "00d81864-757c-4449-a91c-cf6bee07e44a",
// "https://env0.com/templateName": "single-use-template-for-teleport-env0-demo",
// "https://env0.com/workspaceName": "teleport-env0-demo-000000",
// "iat": 1761106671,
// "iss": "https://login.app.env0.com/",
// "organization": "948de0c4-94d6-4ad6-8e56-1374353e9a38",
// "organizationId": "948de0c4-94d6-4ad6-8e56-1374353e9a38",
// "projectId": "df15f983-808a-49c7-bc91-910cb10411ec",
// "projectName": "My First Project",
// "sub": "auth0|68f8497fe94b94dab2324697",
// "templateId": "00d81864-757c-4449-a91c-cf6bee07e44a",
// "templateName": "single-use-template-for-teleport-env0-demo",
// "workspaceName": "teleport-env0-demo-000000"
// }
type IDTokenClaims struct {
oidc.TokenClaims
// OrganizationID is a unique identifier for the organization. Corresponds
// to `organizationId`.
OrganizationID string `json:"organizationId"`
// ProjectID is a unique identifier for the project. Corresponds to
// `projectId`.
ProjectID string `json:"projectId"`
// ProjectName is the name of the project. Corresponds to `projectName`.
ProjectName string `json:"projectName"`
// TemplateID is a unique identifier for the template. Corresponds to
// `templateId`.
TemplateID string `json:"templateId"`
// TemplateName is the name of the template. Corresponds to `templateName`.
TemplateName string `json:"templateName"`
// EnvironmentID is a unique identifier for the environment. Corresponds to
// `environmentId`.
EnvironmentID string `json:"environmentId"`
// EnvironmentName is the name of the environment. Corresponds to
// `environmentName`.
EnvironmentName string `json:"environmentName"`
// WorkspaceName is the name of the workspace. Corresponds to
// `workspaceName`.
WorkspaceName string `json:"workspaceName"`
// DeploymentLogID is a unique identifier for this deployment. Corresponds
// to `deploymentLogId`.
DeploymentLogID string `json:"deploymentLogId"`
// DeploymentType is the type of this deployment. Corresponds to
// `deploymentType`.
DeploymentType string `json:"deploymentType"`
// DeployerEmail is the email of the user that started this deployment.
// Corresponds to `deployerEmail`.
DeployerEmail string `json:"deployerEmail"`
// Env0Tag is an optional custom tag. Corresponds to `env0Tag`.
Env0Tag string `json:"env0Tag"`
}
func (c *IDTokenClaims) JoinAttrs() *workloadidentityv1pb.JoinAttrsEnv0 {
return &workloadidentityv1pb.JoinAttrsEnv0{
Sub: c.Subject,
OrganizationId: c.OrganizationID,
ProjectId: c.ProjectID,
ProjectName: c.ProjectName,
TemplateId: c.TemplateID,
TemplateName: c.TemplateName,
EnvironmentId: c.EnvironmentID,
EnvironmentName: c.EnvironmentName,
WorkspaceName: c.WorkspaceName,
DeploymentLogId: c.DeploymentLogID,
DeploymentType: c.DeploymentType,
DeployerEmail: c.DeployerEmail,
Env0Tag: c.Env0Tag,
}
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package env0
import (
"github.com/gravitational/trace"
)
type envGetter func(key string) string
// IDTokenSource allows a Env0 OIDC token to be fetched whilst within a job
// execution.
type IDTokenSource struct {
getEnv envGetter
}
// GetIDToken fetches an Env0 JWT from the local node's environment
func (its *IDTokenSource) GetIDToken() (string, error) {
name := "ENV0_OIDC_TOKEN"
tok := its.getEnv(name)
if tok == "" {
return "", trace.BadParameter(
"%s environment variable missing, ensure 'Enable OIDC during deployments' is enabled in the workspace",
name,
)
}
return tok, nil
}
// NewIDTokenSource creates a new Env0 ID token source with the given audience
// tag.
func NewIDTokenSource(getEnv envGetter) *IDTokenSource {
return &IDTokenSource{
getEnv,
}
}
+80
View File
@@ -0,0 +1,80 @@
/*
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package env0
import (
"context"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/zitadel/oidc/v3/pkg/client/rp"
"github.com/gravitational/teleport/lib/oidc"
)
const (
// env0IssuerURL is the env0 public issuer URL
env0IssuerURL = "https://login.app.env0.com/"
// env0Audience is the audience for the token. This is unfortunately hard
// coded.
env0Audience = "https://prod.env0.com"
)
// IDTokenValidator can be used to validate env0 OIDC tokens.
type IDTokenValidator struct {
validator *oidc.CachingTokenValidator[*IDTokenClaims]
}
// ValidateToken validates an env0 OIDC token using a remote, cached OIDC
// endpoint
func (v *IDTokenValidator) ValidateToken(
ctx context.Context,
token []byte,
) (*IDTokenClaims, error) {
validator, err := v.validator.GetValidator(ctx, env0IssuerURL, env0Audience)
if err != nil {
return nil, trace.Wrap(err)
}
// Env0 issues tokens with a randomized azp, which we can't verify. It's
// an optional check, so we'll disable it.
withoutAZPVerifier := rp.WithAZPVerifier(func(string) error {
return nil
})
claims, err := validator.ValidateToken(ctx, string(token), withoutAZPVerifier)
if err != nil {
return nil, trace.Wrap(err, "validating OIDC token")
}
return claims, nil
}
// NewOIDCTokenValidator constructs a KubernetesOIDCTokenValidator.
func NewIDTokenValidator() (*IDTokenValidator, error) {
validator, err := oidc.NewCachingTokenValidator[*IDTokenClaims](clockwork.NewRealClock())
if err != nil {
return nil, trace.Wrap(err)
}
return &IDTokenValidator{
validator: validator,
}, nil
}
+16
View File
@@ -194,6 +194,22 @@ func (k *PublicKeys) check() error {
return nil
}
// OIDCInit holds the OIDC identity token used for all OIDC-based join methods.
//
// The join flow for all OIDC-based join methods is:
// 1. client->server: ClientInit
// 2. server->client: ServerInit
// 3. client->server: OIDCInit
// 4. server->client: Result
type OIDCInit struct {
embedRequest
// ClientParams holds parameters for the specific type of client trying to join.
ClientParams ClientParams
// IDToken is the OIDC identity token.
IDToken []byte
}
// BoundKeypairInit is sent from the client in response to the ServerInit
// message for the bound keypair join method.
// The server is expected to respond with a BoundKeypairChallenge.
+15 -1
View File
@@ -23,6 +23,7 @@ import (
"encoding/pem"
"errors"
"log/slog"
"os"
"github.com/gravitational/trace"
"golang.org/x/crypto/ssh"
@@ -32,6 +33,7 @@ import (
authjoin "github.com/gravitational/teleport/lib/auth/join"
proxyinsecureclient "github.com/gravitational/teleport/lib/client/proxy/insecure"
"github.com/gravitational/teleport/lib/cryptosuites"
"github.com/gravitational/teleport/lib/join/env0"
"github.com/gravitational/teleport/lib/join/internal/messages"
"github.com/gravitational/teleport/lib/join/joinv1"
"github.com/gravitational/teleport/lib/utils/hostid"
@@ -162,7 +164,8 @@ func joinWithClient(ctx context.Context, params JoinParams, client *joinv1.Clien
case types.JoinMethodToken,
types.JoinMethodBoundKeypair,
types.JoinMethodIAM,
types.JoinMethodEC2:
types.JoinMethodEC2,
types.JoinMethodEnv0:
joinMethod := string(params.JoinMethod)
joinMethodPtr = &joinMethod
default:
@@ -240,6 +243,8 @@ func joinWithMethod(
clientParams messages.ClientParams,
method string,
) (messages.Response, error) {
var err error
switch types.JoinMethod(method) {
case types.JoinMethodToken:
return tokenJoin(stream, clientParams)
@@ -249,6 +254,15 @@ func joinWithMethod(
return iamJoin(ctx, stream, joinParams, clientParams)
case types.JoinMethodEC2:
return ec2Join(ctx, stream, joinParams, clientParams)
case types.JoinMethodEnv0:
// Tests may specify their own IDToken, so only overwrite it when empty.
if joinParams.IDToken == "" {
joinParams.IDToken, err = env0.NewIDTokenSource(os.Getenv).GetIDToken()
if err != nil {
return nil, trace.Wrap(err)
}
}
return oidcJoin(stream, joinParams, clientParams)
default:
// TODO(nklaassen): implement remaining join methods.
sendGivingUpErr := stream.Send(&messages.GivingUp{
+51
View File
@@ -0,0 +1,51 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package joinclient
import (
"github.com/gravitational/trace"
"github.com/gravitational/teleport/lib/join/internal/messages"
)
// oidcJoin handles stream interactions for most OIDC join methods that provide
// a static OIDC assertion.
func oidcJoin(
stream messages.ClientStream,
joinParams JoinParams,
clientParams messages.ClientParams,
) (messages.Response, error) {
// The OIDC join methods involve the following messages:
//
// client->server ClientInit
// client<-server ServerInit
// client->server OIDCInit
// client<-server Result
//
// At this point the ServerInit messages has already been received, what's
// left is to send the OIDCInit message and receive and return the final
// result.
if err := stream.Send(&messages.OIDCInit{
ClientParams: clientParams,
IDToken: []byte(joinParams.IDToken),
}); err != nil {
return nil, trace.Wrap(err, "sending OIDCInit")
}
result, err := stream.Recv()
return result, trace.Wrap(err, "receiving join result")
}
+12
View File
@@ -38,6 +38,8 @@ func requestToMessage(req *joinv1.JoinRequest) (messages.Request, error) {
return iamInitToMessage(msg.IamInit)
case *joinv1.JoinRequest_Ec2Init:
return ec2InitToMessage(msg.Ec2Init)
case *joinv1.JoinRequest_OidcInit:
return oidcInitToMessage(msg.OidcInit)
case *joinv1.JoinRequest_Solution:
return challengeSolutionToMessage(msg.Solution)
case *joinv1.JoinRequest_GivingUp:
@@ -97,6 +99,16 @@ func requestFromMessage(msg messages.Request) (*joinv1.JoinRequest, error) {
Ec2Init: ec2Init,
},
}, nil
case *messages.OIDCInit:
oidcInit, err := oidcInitFromMessage(typedMsg)
if err != nil {
return nil, trace.Wrap(err)
}
return &joinv1.JoinRequest{
Payload: &joinv1.JoinRequest_OidcInit{
OidcInit: oidcInit,
},
}, nil
case *messages.BoundKeypairChallengeSolution,
*messages.BoundKeypairRotationResponse,
*messages.IAMChallengeSolution:
+46
View File
@@ -0,0 +1,46 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package joinv1
import (
"github.com/gravitational/trace"
joinv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/join/v1"
"github.com/gravitational/teleport/lib/join/internal/messages"
)
func oidcInitToMessage(req *joinv1.OIDCInit) (*messages.OIDCInit, error) {
clientParams, err := clientParamsToMessage(req.ClientParams)
if err != nil {
return nil, trace.Wrap(err)
}
return &messages.OIDCInit{
ClientParams: clientParams,
IDToken: req.IdToken,
}, nil
}
func oidcInitFromMessage(msg *messages.OIDCInit) (*joinv1.OIDCInit, error) {
clientParams, err := clientParamsFromMessage(msg.ClientParams)
if err != nil {
return nil, trace.Wrap(err)
}
return &joinv1.OIDCInit{
ClientParams: clientParams,
IdToken: msg.IDToken,
}, nil
}
+3
View File
@@ -76,6 +76,7 @@ type AuthService interface {
GetClock() clockwork.Clock
GetHTTPClientForAWSSTS() utils.HTTPDoClient
GetEC2ClientForEC2JoinMethod() ec2join.EC2Client
GetEnv0IDTokenValidator() Env0TokenValidator
services.Presence
}
@@ -211,6 +212,8 @@ func (s *Server) handleJoinMethod(
return s.handleIAMJoin(stream, authCtx, clientInit, provisionToken)
case types.JoinMethodEC2:
return s.handleEC2Join(stream, authCtx, clientInit, provisionToken)
case types.JoinMethodEnv0:
return s.handleOIDCJoin(stream, authCtx, clientInit, provisionToken, s.validateEnv0Token)
default:
// TODO(nklaassen): implement checks for all join methods.
return nil, trace.NotImplemented("join method %s is not yet implemented by the new join service", joinMethod)
+103
View File
@@ -0,0 +1,103 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package join
import (
"context"
"github.com/gravitational/trace"
workloadidentityv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/join/env0"
)
type Env0TokenValidator interface {
ValidateToken(
ctx context.Context,
token []byte,
) (*env0.IDTokenClaims, error)
}
// validateEnv0Token performs OIDC token verification for Env0-type JWTs,
// suitable for use in `handleOIDCJoin`
func (s *Server) validateEnv0Token(
ctx context.Context,
provisionToken types.ProvisionToken,
idToken []byte,
) (any, *workloadidentityv1.JoinAttrs, error) {
verifiedIdentity, err := s.cfg.AuthService.GetEnv0IDTokenValidator().ValidateToken(ctx, idToken)
if err != nil {
return nil, nil, trace.Wrap(err, "validating Env0 OIDC token")
}
ptv2, ok := provisionToken.(*types.ProvisionTokenV2)
if !ok {
return nil, nil, trace.BadParameter("expected *types.ProvisionTokenV2, got %T", provisionToken)
}
if err := checkEnv0AllowRules(ptv2, verifiedIdentity); err != nil {
return nil, nil, trace.Wrap(err)
}
return verifiedIdentity, &workloadidentityv1.JoinAttrs{
Env0: verifiedIdentity.JoinAttrs(),
}, nil
}
func checkEnv0AllowRules(token *types.ProvisionTokenV2, claims *env0.IDTokenClaims) error {
for _, rule := range token.Spec.Env0.Allow {
if rule.OrganizationID != "" && claims.OrganizationID != rule.OrganizationID {
continue
}
if rule.ProjectID != "" && claims.ProjectID != rule.ProjectID {
continue
}
if rule.ProjectName != "" && claims.ProjectName != rule.ProjectName {
continue
}
if rule.TemplateID != "" && claims.TemplateID != rule.TemplateID {
continue
}
if rule.TemplateName != "" && claims.TemplateName != rule.TemplateName {
continue
}
if rule.EnvironmentID != "" && claims.EnvironmentID != rule.EnvironmentID {
continue
}
if rule.EnvironmentName != "" && claims.EnvironmentName != rule.EnvironmentName {
continue
}
if rule.WorkspaceName != "" && claims.WorkspaceName != rule.WorkspaceName {
continue
}
if rule.DeploymentType != "" && claims.DeploymentType != rule.DeploymentType {
continue
}
if rule.DeployerEmail != "" && claims.DeployerEmail != rule.DeployerEmail {
continue
}
if rule.Env0Tag != "" && claims.Env0Tag != rule.Env0Tag {
continue
}
// All provided rules met.
return nil
}
return trace.AccessDenied("id token claims did not match any allow rules")
}
+486
View File
@@ -0,0 +1,486 @@
/*
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package join_test
import (
"context"
"testing"
"time"
"github.com/gravitational/trace"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/authtest"
"github.com/gravitational/teleport/lib/auth/state"
"github.com/gravitational/teleport/lib/join/env0"
"github.com/gravitational/teleport/lib/join/joinclient"
)
type mockEnv0Validator struct {
claims *env0.IDTokenClaims
idToken string
}
func (m *mockEnv0Validator) ValidateToken(ctx context.Context, token []byte) (*env0.IDTokenClaims, error) {
if string(token) == m.idToken {
return m.claims, nil
}
return nil, trace.AccessDenied("invalid token")
}
type env0JoinTestCase struct {
desc string
tokenName string
requestTokenName string
tokenSpec types.ProvisionTokenSpecV2
oidcToken string
validator *mockEnv0Validator
assertError require.ErrorAssertionFunc
}
func TestJoinEnv0(t *testing.T) {
t.Parallel()
ctx := t.Context()
authServer, err := authtest.NewTestServer(authtest.ServerConfig{
Auth: authtest.AuthServerConfig{
Dir: t.TempDir(),
},
})
require.NoError(t, err)
t.Cleanup(func() { assert.NoError(t, authServer.Shutdown(ctx)) })
// Define some fake names and IDs the fake "provider" will issue.
const (
defaultSubject = "subject"
defaultOrganizationID = "organization-id"
defaultProjectID = "project-id"
defaultProjectName = "project-name"
defaultTemplateID = "template-id"
defaultTemplateName = "template-name"
defaultEnvironmentID = "environment-id "
defaultEnvironmentName = "environment-name"
defaultWorkspaceName = "workspace-name"
defaultDeploymentType = "deployment-type"
defaultDeployerEmail = "deployer-email"
defaultCustomTag = "custom-tag"
)
validator := func(expectToken string, mutator ...func(*env0.IDTokenClaims)) *mockEnv0Validator {
claims := &env0.IDTokenClaims{
TokenClaims: oidc.TokenClaims{
Subject: defaultSubject,
},
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
ProjectName: defaultProjectName,
TemplateID: defaultTemplateID,
TemplateName: defaultTemplateName,
EnvironmentID: defaultEnvironmentID,
EnvironmentName: defaultEnvironmentName,
WorkspaceName: defaultWorkspaceName,
DeploymentType: defaultDeploymentType,
DeployerEmail: defaultDeployerEmail,
Env0Tag: defaultCustomTag,
DeploymentLogID: "foo",
}
for _, m := range mutator {
m(claims)
}
return &mockEnv0Validator{
idToken: expectToken,
claims: claims,
}
}
isAccessDenied := func(t require.TestingT, err error, msgAndArgs ...any) {
require.ErrorAs(t, err, new(*trace.AccessDeniedError), msgAndArgs...)
}
testCases := []env0JoinTestCase{
{
desc: "basic passing case",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
},
},
},
},
assertError: require.NoError,
},
{
desc: "passes with all rules configured",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
// Include a rule that won't match for good measure.
OrganizationID: "nope",
ProjectName: "also nope",
},
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
ProjectName: defaultProjectName,
TemplateID: defaultTemplateID,
TemplateName: defaultTemplateName,
EnvironmentID: defaultEnvironmentID,
EnvironmentName: defaultEnvironmentName,
WorkspaceName: defaultWorkspaceName,
DeploymentType: defaultDeploymentType,
DeployerEmail: defaultDeployerEmail,
Env0Tag: defaultCustomTag,
},
},
},
},
assertError: require.NoError,
},
{
desc: "requested wrong token",
tokenName: "test-token",
requestTokenName: "wrong-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "oidc token fails validation",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "invalid-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong organization",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "other-org-id",
ProjectID: defaultProjectID,
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong project id",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: "other-project-id",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong project name",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
ProjectName: "other-project-name",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong template id",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
TemplateID: "other-template-id",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong template name",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
TemplateName: "other-template-name",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong environment id",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
EnvironmentID: "other-environment-id",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong environment name",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
EnvironmentName: "other-environment-name",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong workspace name",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
WorkspaceName: "other-workspace-name",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong deployment type",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
DeploymentType: "other-deployment-type",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong deployer email",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
DeployerEmail: "other-deployer-email",
},
},
},
},
assertError: isAccessDenied,
},
{
desc: "wrong custom tag",
tokenName: "test-token",
requestTokenName: "test-token",
oidcToken: "correct-token",
validator: validator("correct-token"),
tokenSpec: types.ProvisionTokenSpecV2{
Roles: []types.SystemRole{types.RoleNode},
JoinMethod: types.JoinMethodEnv0,
Env0: &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: defaultOrganizationID,
ProjectID: defaultProjectID,
Env0Tag: "other-custom-tag",
},
},
},
},
assertError: isAccessDenied,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
testEnv0Join(t, authServer, &tc)
})
}
}
func testEnv0Join(t *testing.T, authServer *authtest.Server, tc *env0JoinTestCase) {
ctx := t.Context()
// Set mock client.
authServer.Auth().SetEnv0IDTokenValidator(tc.validator)
// Add token to auth server.
token, err := types.NewProvisionTokenFromSpec(
tc.tokenName,
time.Now().Add(time.Minute),
tc.tokenSpec)
require.NoError(t, err)
require.NoError(t, authServer.Auth().UpsertToken(ctx, token))
t.Cleanup(func() {
assert.NoError(t, authServer.Auth().DeleteToken(ctx, token.GetName()))
})
// Make an unauthenticated auth client that will be used for the join.
nopClient, err := authServer.NewClient(authtest.TestNop())
require.NoError(t, err)
defer nopClient.Close()
// Tests joining via the new join service with auth-assigned host UUIDs.
_, err = joinclient.Join(ctx, joinclient.JoinParams{
Token: tc.requestTokenName,
ID: state.IdentityID{
Role: types.RoleInstance,
NodeName: "test-node",
},
// joinWithMethod only creates a tokenSource when this is unset
IDToken: tc.oidcToken,
AuthClient: nopClient,
})
tc.assertError(t, err)
}
+76
View File
@@ -0,0 +1,76 @@
/*
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package join
import (
"context"
"github.com/gravitational/trace"
workloadidentityv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/join/internal/authz"
"github.com/gravitational/teleport/lib/join/internal/diagnostic"
"github.com/gravitational/teleport/lib/join/internal/messages"
)
// oidcTokenValidator is a function type that validates an OIDC token and checks that
// it matches an allow rule configured in the provision token.
type oidcTokenValidator func(
ctx context.Context,
provisionToken types.ProvisionToken,
idToken []byte,
) (rawClaims any, joinAttrs *workloadidentityv1.JoinAttrs, err error)
// handleOIDCJoin handles join attempts for all generic OIDC join methods.
func (s *Server) handleOIDCJoin(
stream messages.ServerStream,
authCtx *authz.Context,
clientInit *messages.ClientInit,
provisionToken types.ProvisionToken,
validator oidcTokenValidator,
) (messages.Response, error) {
// Receive the OIDCInit message from the client.
oidcInit, err := messages.RecvRequest[*messages.OIDCInit](stream)
if err != nil {
return nil, trace.Wrap(err)
}
// Set any diagnostic info from the ClientParams.
setDiagnosticClientParams(stream.Diagnostic(), &oidcInit.ClientParams)
rawClaims, joinAttrs, err := validator(stream.Context(), provisionToken, oidcInit.IDToken)
stream.Diagnostic().Set(func(info *diagnostic.Info) {
info.RawJoinAttrs = rawClaims
})
if err != nil {
return nil, trace.Wrap(err, "verifying OIDC token")
}
result, err := s.makeResult(
stream.Context(),
stream.Diagnostic(),
authCtx,
clientInit,
&oidcInit.ClientParams,
provisionToken,
rawClaims,
joinAttrs,
)
return result, trace.Wrap(err)
}
+1
View File
@@ -49,6 +49,7 @@ var SupportedJoinMethods = []string{
string(types.JoinMethodTerraformCloud),
string(types.JoinMethodOracle),
string(types.JoinMethodBoundKeypair),
string(types.JoinMethodEnv0),
}
const (
+2 -1
View File
@@ -74,7 +74,8 @@ func Generate(ctx context.Context, joinMethod types.JoinMethod) (string, error)
types.JoinMethodGCP,
types.JoinMethodTPM,
types.JoinMethodTerraformCloud,
types.JoinMethodOracle:
types.JoinMethodOracle,
types.JoinMethodEnv0:
// Checking error instead of the usual uuid.New() in case uuid generation
// fails due to not enough randomness. It's been known to happen happen when
// Teleport starts very early in the node initialization cycle and /dev/urandom
+9
View File
@@ -761,6 +761,15 @@ func setMinimalConfigForMethod(spec *types.ProvisionTokenSpecV2, method types.Jo
Mode: boundkeypair.RecoveryModeInsecure,
},
}
case types.JoinMethodEnv0:
spec.Env0 = &types.ProvisionTokenSpecV2Env0{
Allow: []*types.ProvisionTokenSpecV2Env0_Rule{
{
OrganizationID: "example-organization-id",
ProjectName: "example-project-name",
},
},
}
}
}