feat: add IAM user access key management

Add `CreateAccessKey`, `UpdateAccessKey`, `DeleteAccessKey`, `ListAccessKeys`, and `GetAccessKeyLastUsed` actions for managing user access keys and retrieving their latest usage details.

Generate AWS-style access key IDs and secrets, validate key identifiers and statuses, enforce per-user key quotas, and prevent deleting users that still own access keys. Persist access keys across internal and Vault storage backends with ownership indexing, pagination, and IAM-compatible errors and XML responses.
This commit is contained in:
niksis02
2026-08-15 17:38:26 +04:00
parent 3227a629dc
commit a884d52af4
19 changed files with 2129 additions and 27 deletions
+121
View File
@@ -0,0 +1,121 @@
// Copyright 2026 Versity Software
// This file is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package types
import (
"encoding/xml"
"time"
)
type CreateAccessKeyResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ CreateAccessKeyResponse"`
Result CreateAccessKeyResult `xml:"CreateAccessKeyResult"`
ResponseMetadata ResponseMetadata
}
func (r *CreateAccessKeyResponse) SetRequestID(requestID string) {
r.ResponseMetadata.RequestID = requestID
}
type CreateAccessKeyResult struct {
AccessKey AccessKey
}
type AccessKey struct {
UserName string `xml:",omitempty"`
AccessKeyId string
Status string
SecretAccessKey string
CreateDate time.Time
}
type UpdateAccessKeyResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ UpdateAccessKeyResponse"`
ResponseMetadata ResponseMetadata
}
func (r *UpdateAccessKeyResponse) SetRequestID(requestID string) {
r.ResponseMetadata.RequestID = requestID
}
type DeleteAccessKeyResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ DeleteAccessKeyResponse"`
ResponseMetadata ResponseMetadata
}
func (r *DeleteAccessKeyResponse) SetRequestID(requestID string) {
r.ResponseMetadata.RequestID = requestID
}
type GetAccessKeyLastUsedResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ GetAccessKeyLastUsedResponse"`
Result GetAccessKeyLastUsedResult `xml:"GetAccessKeyLastUsedResult"`
ResponseMetadata ResponseMetadata
}
func (r *GetAccessKeyLastUsedResponse) SetRequestID(requestID string) {
r.ResponseMetadata.RequestID = requestID
}
type GetAccessKeyLastUsedResult struct {
UserName string `xml:",omitempty"`
AccessKeyLastUsed AccessKeyLastUsed
}
type AccessKeyLastUsed struct {
LastUsedDate *time.Time `xml:",omitempty"`
ServiceName string
Region string
}
type ListAccessKeysResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListAccessKeysResponse"`
Result ListAccessKeysResult `xml:"ListAccessKeysResult"`
ResponseMetadata ResponseMetadata
}
func (r *ListAccessKeysResponse) SetRequestID(requestID string) {
r.ResponseMetadata.RequestID = requestID
}
type ListAccessKeysResult struct {
AccessKeyMetadata AccessKeyMetadataList
IsTruncated bool
Marker string `xml:",omitempty"`
}
type AccessKeyMetadataList struct {
Members []AccessKeyMetadata `xml:"member"`
}
type AccessKeyMetadata struct {
UserName string `xml:",omitempty"`
AccessKeyId string
Status string
CreateDate time.Time
}
// AccessKeyEntry is the storage representation of an access key belonging to
// a User. It is never marshaled to XML directly; it round-trips through JSON
// for the internal and Vault storers.
type AccessKeyEntry struct {
AccessKeyId string
SecretAccessKey string
Status string
CreateDate time.Time
LastUsedDate time.Time
LastUsedService string
LastUsedRegion string
}
+7 -6
View File
@@ -99,12 +99,13 @@ func (r *DeleteUserResponse) SetRequestID(requestID string) {
}
type User struct {
Path string `xml:",omitempty"`
UserName string `xml:",omitempty"`
UserID string `xml:"UserId"`
Arn string `xml:"Arn"`
CreateDate time.Time `xml:"CreateDate"`
Tags []Tag `xml:"Tags>member,omitempty"`
Path string `xml:",omitempty"`
UserName string `xml:",omitempty"`
UserID string `xml:"UserId"`
Arn string `xml:"Arn"`
CreateDate time.Time `xml:"CreateDate"`
Tags []Tag `xml:"Tags>member,omitempty"`
AccessKeys []AccessKeyEntry `xml:"-"`
}
type Tag struct {