diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go index a4e996a27e9b5..1b443c434790c 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go @@ -148,6 +148,8 @@ type AccessMonitoringRuleSpec struct { DesiredState string `protobuf:"bytes,7,opt,name=desired_state,json=desiredState,proto3" json:"desired_state,omitempty"` // schedules specifies a map of schedules that can be used to configure the // access monitoring rule conditions. + // + // Available in Teleport v18.2.8 or higher. Schedules map[string]*Schedule `protobuf:"bytes,8,rep,name=schedules,proto3" json:"schedules,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -394,8 +396,14 @@ func (x *Schedule) GetTime() *TimeSchedule { type TimeSchedule struct { state protoimpl.MessageState `protogen:"open.v1"` // Shifts contains a set of shifts that make up the schedule. - // Shifts are configured in UTC. - Shifts []*TimeSchedule_Shift `protobuf:"bytes,1,rep,name=shifts,proto3" json:"shifts,omitempty"` + Shifts []*TimeSchedule_Shift `protobuf:"bytes,1,rep,name=shifts,proto3" json:"shifts,omitempty"` + // Timezone specifies the schedule timezone. This field is optional and defaults + // to "UTC". Accepted values use timezone locations as defined in the IANA + // Time Zone Database, such as "America/Los_Angeles", "Europe/Lisbon", or + // "Asia/Singapore". + // + // See https://data.iana.org/time-zones/tzdb/zone1970.tab for a list of supported values. + Timezone string `protobuf:"bytes,2,opt,name=timezone,proto3" json:"timezone,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -437,6 +445,13 @@ func (x *TimeSchedule) GetShifts() []*TimeSchedule_Shift { return nil } +func (x *TimeSchedule) GetTimezone() string { + if x != nil { + return x.Timezone + } + return "" +} + // CreateAccessMonitoringRuleRequest is the request for CreateAccessMonitoringRule. type CreateAccessMonitoringRuleRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1014,9 +1029,10 @@ const file_teleport_accessmonitoringrules_v1_access_monitoring_rules_proto_rawDe "\vintegration\x18\x01 \x01(\tR\vintegration\x12\x1a\n" + "\bdecision\x18\x02 \x01(\tR\bdecision\"O\n" + "\bSchedule\x12C\n" + - "\x04time\x18\x01 \x01(\v2/.teleport.accessmonitoringrules.v1.TimeScheduleR\x04time\"\xa8\x01\n" + + "\x04time\x18\x01 \x01(\v2/.teleport.accessmonitoringrules.v1.TimeScheduleR\x04time\"\xc4\x01\n" + "\fTimeSchedule\x12M\n" + - "\x06shifts\x18\x01 \x03(\v25.teleport.accessmonitoringrules.v1.TimeSchedule.ShiftR\x06shifts\x1aI\n" + + "\x06shifts\x18\x01 \x03(\v25.teleport.accessmonitoringrules.v1.TimeSchedule.ShiftR\x06shifts\x12\x1a\n" + + "\btimezone\x18\x02 \x01(\tR\btimezone\x1aI\n" + "\x05Shift\x12\x18\n" + "\aweekday\x18\x01 \x01(\tR\aweekday\x12\x14\n" + "\x05start\x18\x02 \x01(\tR\x05start\x12\x10\n" + diff --git a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto index 13ebe953a10a6..df9c7e1a0d423 100644 --- a/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto +++ b/api/proto/teleport/accessmonitoringrules/v1/access_monitoring_rules.proto @@ -70,6 +70,8 @@ message AccessMonitoringRuleSpec { // schedules specifies a map of schedules that can be used to configure the // access monitoring rule conditions. + // + // Available in Teleport v18.2.8 or higher. map schedules = 8; } @@ -100,9 +102,16 @@ message Schedule { // TimeSchedule specifies an in-line schedule. message TimeSchedule { // Shifts contains a set of shifts that make up the schedule. - // Shifts are configured in UTC. repeated Shift shifts = 1; + // Timezone specifies the schedule timezone. This field is optional and defaults + // to "UTC". Accepted values use timezone locations as defined in the IANA + // Time Zone Database, such as "America/Los_Angeles", "Europe/Lisbon", or + // "Asia/Singapore". + // + // See https://data.iana.org/time-zones/tzdb/zone1970.tab for a list of supported values. + string timezone = 2; + // Shift contains the weekday, start time, and end time of a shift. message Shift { // Weekday specifies the day of the week, e.g., "Sunday", "Monday", "Tuesday". diff --git a/docs/pages/reference/infrastructure-as-code/terraform-provider/data-sources/access_monitoring_rule.mdx b/docs/pages/reference/infrastructure-as-code/terraform-provider/data-sources/access_monitoring_rule.mdx index 6c8aebaa15467..8d15d61d01dee 100644 --- a/docs/pages/reference/infrastructure-as-code/terraform-provider/data-sources/access_monitoring_rule.mdx +++ b/docs/pages/reference/infrastructure-as-code/terraform-provider/data-sources/access_monitoring_rule.mdx @@ -43,7 +43,7 @@ Optional: - `condition` (String) condition is a predicate expression that operates on the specified subject resources, and determines whether the subject will be moved into desired state. - `desired_state` (String) desired_state defines the desired state of the subject. For Access Request subjects, the desired_state may be set to `reviewed` to indicate that the Access Request should be automatically reviewed. - `notification` (Attributes) notification defines the plugin configuration for notifications if rule is triggered. Both notification and automatic_review may be set within the same access_monitoring_rule. If both fields are set, the rule will trigger both notifications and automatic reviews for the same set of access events. Separate plugins may be used if both notifications and automatic_reviews is set. (see [below for nested schema](#nested-schema-for-specnotification)) -- `schedules` (Attributes Map) schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions. (see [below for nested schema](#nested-schema-for-specschedules)) +- `schedules` (Attributes Map) schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions. Available in Teleport v18.2.8 or higher. (see [below for nested schema](#nested-schema-for-specschedules)) - `states` (List of String) states are the desired state which the monitoring rule is attempting to bring the subjects matching the condition to. ### Nested Schema for `spec.automatic_review` @@ -72,7 +72,8 @@ Optional: Optional: -- `shifts` (Attributes List) Shifts contains a set of shifts that make up the schedule. Shifts are configured in UTC. (see [below for nested schema](#nested-schema-for-specschedulestimeshifts)) +- `shifts` (Attributes List) Shifts contains a set of shifts that make up the schedule. (see [below for nested schema](#nested-schema-for-specschedulestimeshifts)) +- `timezone` (String) Timezone specifies the schedule timezone. This field is optional and defaults to "UTC". Accepted values use timezone locations as defined in the IANA Time Zone Database, such as "America/Los_Angeles", "Europe/Lisbon", or "Asia/Singapore". See https://data.iana.org/time-zones/tzdb/zone1970.tab for a list of supported values. ### Nested Schema for `spec.schedules.time.shifts` diff --git a/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/access_monitoring_rule.mdx b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/access_monitoring_rule.mdx index 543599e6f9d74..74f656b5cac0b 100644 --- a/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/access_monitoring_rule.mdx +++ b/docs/pages/reference/infrastructure-as-code/terraform-provider/resources/access_monitoring_rule.mdx @@ -65,7 +65,7 @@ Optional: - `condition` (String) condition is a predicate expression that operates on the specified subject resources, and determines whether the subject will be moved into desired state. - `desired_state` (String) desired_state defines the desired state of the subject. For Access Request subjects, the desired_state may be set to `reviewed` to indicate that the Access Request should be automatically reviewed. - `notification` (Attributes) notification defines the plugin configuration for notifications if rule is triggered. Both notification and automatic_review may be set within the same access_monitoring_rule. If both fields are set, the rule will trigger both notifications and automatic reviews for the same set of access events. Separate plugins may be used if both notifications and automatic_reviews is set. (see [below for nested schema](#nested-schema-for-specnotification)) -- `schedules` (Attributes Map) schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions. (see [below for nested schema](#nested-schema-for-specschedules)) +- `schedules` (Attributes Map) schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions. Available in Teleport v18.2.8 or higher. (see [below for nested schema](#nested-schema-for-specschedules)) - `states` (List of String) states are the desired state which the monitoring rule is attempting to bring the subjects matching the condition to. ### Nested Schema for `spec.automatic_review` @@ -94,7 +94,8 @@ Optional: Optional: -- `shifts` (Attributes List) Shifts contains a set of shifts that make up the schedule. Shifts are configured in UTC. (see [below for nested schema](#nested-schema-for-specschedulestimeshifts)) +- `shifts` (Attributes List) Shifts contains a set of shifts that make up the schedule. (see [below for nested schema](#nested-schema-for-specschedulestimeshifts)) +- `timezone` (String) Timezone specifies the schedule timezone. This field is optional and defaults to "UTC". Accepted values use timezone locations as defined in the IANA Time Zone Database, such as "America/Los_Angeles", "Europe/Lisbon", or "Asia/Singapore". See https://data.iana.org/time-zones/tzdb/zone1970.tab for a list of supported values. ### Nested Schema for `spec.schedules.time.shifts` diff --git a/integrations/terraform/tfschema/accessmonitoringrules/v1/access_monitoring_rules_terraform.go b/integrations/terraform/tfschema/accessmonitoringrules/v1/access_monitoring_rules_terraform.go index 0fa3920979e3c..c7ebd95994ead 100644 --- a/integrations/terraform/tfschema/accessmonitoringrules/v1/access_monitoring_rules_terraform.go +++ b/integrations/terraform/tfschema/accessmonitoringrules/v1/access_monitoring_rules_terraform.go @@ -142,31 +142,38 @@ func GenSchemaAccessMonitoringRule(ctx context.Context) (github_com_hashicorp_te }, "schedules": { Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.MapNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"time": { - Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"shifts": { - Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ - "end": { - Description: "End specifies the end time in the format HH:MM, e.g., \"12:30\".", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, - }, - "start": { - Description: "Start specifies the start time in the format HH:MM, e.g., \"12:30\".", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, - }, - "weekday": { - Description: "Weekday specifies the day of the week, e.g., \"Sunday\", \"Monday\", \"Tuesday\".", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, - }, - }), - Description: "Shifts contains a set of shifts that make up the schedule. Shifts are configured in UTC.", - Optional: true, - }}), + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "shifts": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "end": { + Description: "End specifies the end time in the format HH:MM, e.g., \"12:30\".", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "start": { + Description: "Start specifies the start time in the format HH:MM, e.g., \"12:30\".", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "weekday": { + Description: "Weekday specifies the day of the week, e.g., \"Sunday\", \"Monday\", \"Tuesday\".", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Shifts contains a set of shifts that make up the schedule.", + Optional: true, + }, + "timezone": { + Description: "Timezone specifies the schedule timezone. This field is optional and defaults to \"UTC\". Accepted values use timezone locations as defined in the IANA Time Zone Database, such as \"America/Los_Angeles\", \"Europe/Lisbon\", or \"Asia/Singapore\". See https://data.iana.org/time-zones/tzdb/zone1970.tab for a list of supported values.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), Description: "TimeSchedule specifies an in-line schedule.", Optional: true, }}), - Description: "schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions.", + Description: "schedules specifies a map of schedules that can be used to configure the access monitoring rule conditions. Available in Teleport v18.2.8 or higher.", Optional: true, }, "states": { @@ -701,6 +708,23 @@ func CopyAccessMonitoringRuleFromTerraform(_ context.Context, tf github_com_hash } } } + { + a, ok := tf.Attrs["timezone"] + if !ok { + diags.Append(attrReadMissingDiag{"AccessMonitoringRule.spec.schedules.time.timezone"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"AccessMonitoringRule.spec.schedules.time.timezone", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Timezone = t + } + } + } } } } @@ -1524,6 +1548,28 @@ func CopyAccessMonitoringRuleToTerraform(ctx context.Context, obj *github_com_gr } } } + { + t, ok := tf.AttrTypes["timezone"] + if !ok { + diags.Append(attrWriteMissingDiag{"AccessMonitoringRule.spec.schedules.time.timezone"}) + } else { + v, ok := tf.Attrs["timezone"].(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{"AccessMonitoringRule.spec.schedules.time.timezone", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"AccessMonitoringRule.spec.schedules.time.timezone", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Timezone) == "" + } + v.Value = string(obj.Timezone) + v.Unknown = false + tf.Attrs["timezone"] = v + } + } } v.Unknown = false tf.Attrs["time"] = v diff --git a/lib/services/access_monitoring_rules.go b/lib/services/access_monitoring_rules.go index 8fbdcf4e37f1c..6ff8c60b9e18d 100644 --- a/lib/services/access_monitoring_rules.go +++ b/lib/services/access_monitoring_rules.go @@ -22,6 +22,7 @@ import ( "context" "slices" "time" + _ "time/tzdata" "github.com/gravitational/trace" @@ -156,6 +157,10 @@ func validateSchedules(schedules map[string]*accessmonitoringrulesv1.Schedule) e } func validateTimeSchedule(schedule *accessmonitoringrulesv1.TimeSchedule) error { + if _, err := time.LoadLocation(schedule.GetTimezone()); err != nil { + return trace.Wrap(err, "invalid timezone: refer to the IANA Time Zone Database for valid options") + } + if len(schedule.GetShifts()) == 0 { return trace.BadParameter("at least one shift is required") } diff --git a/lib/services/access_monitoring_rules_test.go b/lib/services/access_monitoring_rules_test.go index 4f45ed8d47c7c..d666d2523ce5f 100644 --- a/lib/services/access_monitoring_rules_test.go +++ b/lib/services/access_monitoring_rules_test.go @@ -249,6 +249,98 @@ func TestValidateSchedules(t *testing.T) { require.ErrorContains(t, err, "at least one shift is require") }, }, + { + description: "valid timezone (UTC)", + schedules: map[string]*accessmonitoringrulesv1.Schedule{ + "default": { + Time: &accessmonitoringrulesv1.TimeSchedule{ + Timezone: "UTC", + Shifts: []*accessmonitoringrulesv1.TimeSchedule_Shift{ + { + Weekday: time.Monday.String(), + Start: "00:00", + End: "23:59", + }, + }, + }, + }, + }, + assertErr: require.NoError, + }, + { + description: "valid timezone (America/Los_Angeles)", + schedules: map[string]*accessmonitoringrulesv1.Schedule{ + "default": { + Time: &accessmonitoringrulesv1.TimeSchedule{ + Timezone: "America/Los_Angeles", + Shifts: []*accessmonitoringrulesv1.TimeSchedule_Shift{ + { + Weekday: time.Monday.String(), + Start: "00:00", + End: "23:59", + }, + }, + }, + }, + }, + assertErr: require.NoError, + }, + { + description: "valid timezone (Europe/Lisbon)", + schedules: map[string]*accessmonitoringrulesv1.Schedule{ + "default": { + Time: &accessmonitoringrulesv1.TimeSchedule{ + Timezone: "Europe/Lisbon", + Shifts: []*accessmonitoringrulesv1.TimeSchedule_Shift{ + { + Weekday: time.Monday.String(), + Start: "00:00", + End: "23:59", + }, + }, + }, + }, + }, + assertErr: require.NoError, + }, + { + description: "valid timezone (Asia/Singapore)", + schedules: map[string]*accessmonitoringrulesv1.Schedule{ + "default": { + Time: &accessmonitoringrulesv1.TimeSchedule{ + Timezone: "Asia/Singapore", + Shifts: []*accessmonitoringrulesv1.TimeSchedule_Shift{ + { + Weekday: time.Monday.String(), + Start: "00:00", + End: "23:59", + }, + }, + }, + }, + }, + assertErr: require.NoError, + }, + { + description: "invalid timezone", + schedules: map[string]*accessmonitoringrulesv1.Schedule{ + "default": { + Time: &accessmonitoringrulesv1.TimeSchedule{ + Timezone: "invalid", + Shifts: []*accessmonitoringrulesv1.TimeSchedule_Shift{ + { + Weekday: time.Monday.String(), + Start: "00:00", + End: "23:59", + }, + }, + }, + }, + }, + assertErr: func(t require.TestingT, err error, _ ...interface{}) { + require.ErrorContains(t, err, "invalid timezone") + }, + }, { description: "start time is not before end time", schedules: map[string]*accessmonitoringrulesv1.Schedule{