Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IAM resources #258

Merged
merged 43 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e59470d
add iam components
Icerzack Feb 22, 2024
25ae416
mark fields sensitive
Icerzack Feb 27, 2024
840b1d6
add description
Icerzack Feb 27, 2024
d0eefd7
fix toolchain directive
Icerzack Feb 27, 2024
ca832bd
fixed imports
Icerzack Feb 27, 2024
e4c57bc
fix problems
Icerzack Feb 29, 2024
b023431
docs and fixes
Icerzack Mar 1, 2024
4b81814
fix unresolved threads
Icerzack Mar 4, 2024
cf37310
add migration guide
Icerzack Mar 4, 2024
e6fc599
rewrite to styleguide
Icerzack Mar 4, 2024
50a3e9d
fix unresolved threads
Icerzack Mar 7, 2024
272893d
add logger calls
Icerzack Mar 7, 2024
f5a4a5c
fix errors in Read
Icerzack Mar 7, 2024
69b1a09
add catalog support
Icerzack Mar 11, 2024
8a44859
update go.mod, go.sum files
Icerzack Mar 11, 2024
15bba3b
Merge branch 'master' into feat/iam
Icerzack Mar 11, 2024
eb86a06
rewrite TypeMap to TypeList for federation
Icerzack Mar 11, 2024
72b891d
update guide
Icerzack Mar 11, 2024
22722be
fix unresolved threads
Icerzack Mar 12, 2024
95c39d9
more fixes
Icerzack Mar 12, 2024
5838184
Merge branch 'master' into feat/iam
Icerzack Mar 19, 2024
86ea264
add missing note blocks
Icerzack Mar 19, 2024
acf6046
Merge branch 'master' into feat/iam
Icerzack Mar 20, 2024
1ba9552
fix linter issues
Icerzack Mar 20, 2024
7d55015
add default auth_region
Icerzack Mar 21, 2024
020ecf4
Merge branch 'master' into feat/iam
Icerzack Mar 27, 2024
0b20609
Rename EC2 to S3Credentials
Icerzack Mar 27, 2024
f9a3850
add missing access_key field
Apr 2, 2024
7a4b2a0
rename ec2 -> s3
Apr 2, 2024
aed8a4f
Merge branch 'master' into feat/iam
Icerzack Apr 2, 2024
7e49a6b
fixing unresolved threads
Apr 9, 2024
705dc9c
updated mirgration guide
Apr 9, 2024
f9876aa
add DefaultAuthRegion
Apr 10, 2024
0804828
add import functionality
Apr 11, 2024
890624b
fixes
Apr 15, 2024
4a31f71
updated docs
Apr 15, 2024
8db5788
remove tables cause they are not rendered properly
Apr 15, 2024
a1b00c8
Merge branch 'master' into feat/iam
Icerzack Apr 17, 2024
3e9cddd
fix s3creds documentation
Apr 17, 2024
52972a3
Merge branch 'master' into feat/iam
Icerzack Apr 17, 2024
d07a485
add roles in docs
Apr 17, 2024
6b9efea
Merge branch 'master' into feat/iam
TruePack Apr 17, 2024
2ffd549
fix linter issues
Apr 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/selectel/dbaas-go v0.12.1
github.com/selectel/domains-go v1.0.2
github.com/selectel/go-selvpcclient/v3 v3.1.1
github.com/selectel/iam-go v0.2.0
github.com/selectel/mks-go v0.14.0
github.com/selectel/secretsmanager-go v0.2.1
github.com/stretchr/testify v1.8.4
Expand All @@ -24,7 +25,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gophercloud/gophercloud v1.5.0 // indirect
github.com/gophercloud/gophercloud v1.10.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo=
github.com/gophercloud/gophercloud v1.5.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/gophercloud v1.10.0 h1:watRMsaMDlSLuLkpLeLSQ87yvcuwIajNg6A5uLcjoIU=
github.com/gophercloud/gophercloud v1.10.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
Expand Down Expand Up @@ -167,6 +167,8 @@ github.com/selectel/domains-go v1.0.2 h1:Si6iGaMnTFJxwiJVI50DOdZnwcxc87kqaWrVQYW
github.com/selectel/domains-go v1.0.2/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
github.com/selectel/go-selvpcclient/v3 v3.1.1 h1:C1q2LqqosiapoLpnGITGmysg0YCSQYDo2Gh69CioevM=
github.com/selectel/go-selvpcclient/v3 v3.1.1/go.mod h1:NM7IXhh1IzqZ88DOw1Qc5Ez3tULLViXo95l5+rKPuyQ=
github.com/selectel/iam-go v0.2.0 h1:c6ldpbsa/8R3b29ML5B21FU9oyJ2A2AwBNzCbE+pGN8=
github.com/selectel/iam-go v0.2.0/go.mod h1:OIAkW7MZK97YUm+uvUgYbgDhkI9SdzTCxwd4yZoOR1o=
github.com/selectel/mks-go v0.14.0 h1:huNq/oTutPc3ezB8HRqlGN9WJubTDETpNKuIVqcZOn0=
github.com/selectel/mks-go v0.14.0/go.mod h1:VxtV3dzwgOEzZc+9VMQb9DvxfSlej2ZQ8jnT8kqIGgU=
github.com/selectel/secretsmanager-go v0.2.1 h1:OSBrA/07lm/Ecpwg59IJHFAoUHZR29oyfwUgTpr/dos=
Expand Down
164 changes: 164 additions & 0 deletions selectel/iam.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package selectel

import (
"errors"
"fmt"
"slices"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/selectel/go-selvpcclient/v3/selvpcclient"
"github.com/selectel/iam-go"
"github.com/selectel/iam-go/service/roles"
"github.com/selectel/iam-go/service/users"
)

const (
importIAMUndefined = "UNDEFINED_WHILE_IMPORTING"
)

func getIAMClient(meta interface{}) (*iam.Client, diag.Diagnostics) {
config := meta.(*Config)

selvpcClient, err := config.GetSelVPCClient()
if err != nil {
return nil, diag.FromErr(fmt.Errorf("can't get selvpc client for iam: %w", err))
}

apiURL, err := getEndpointForIAM(selvpcClient, config.AuthRegion)
if err != nil {
return nil, diag.FromErr(err)
}
iamClient, err := iam.New(
iam.WithAuthOpts(&iam.AuthOpts{
KeystoneToken: selvpcClient.GetXAuthToken(),
}),
iam.WithAPIUrl(apiURL),
)
if err != nil {
return nil, diag.FromErr(fmt.Errorf("can't create iam client: %w", err))
}

return iamClient, nil
}

func getEndpointForIAM(selvpcClient *selvpcclient.Client, region string) (string, error) {
endpoint, err := selvpcClient.Catalog.GetEndpoint(IAM, region)
if err != nil {
return "", fmt.Errorf("can't get endpoint to for iam: %w", err)
}

return endpoint.URL, nil
}

func diffRoles(oldRoles, newRoles []roles.Role) ([]roles.Role, []roles.Role) {
rolesToUnassign := make([]roles.Role, 0)
rolesToAssign := make([]roles.Role, 0)

for _, oldRole := range oldRoles {
if !slices.Contains(newRoles, oldRole) {
rolesToUnassign = append(rolesToUnassign, oldRole)
}
}

for _, newRole := range newRoles {
if !slices.Contains(oldRoles, newRole) {
rolesToAssign = append(rolesToAssign, newRole)
}
}

return rolesToUnassign, rolesToAssign
}

func convertIAMListToUserFederation(federationList []interface{}) (*users.Federation, error) {
if len(federationList) == 0 {
return nil, nil
}
if len(federationList) > 1 {
return nil, errors.New("more than one federation value provided")
}
var idRaw, externalIDRaw interface{}
var ok bool

if idRaw, ok = federationList[0].(map[string]interface{})["id"]; !ok {
return nil, errors.New("federation.id value isn't provided")
}
if externalIDRaw, ok = federationList[0].(map[string]interface{})["external_id"]; !ok {
return nil, errors.New("federation.external_id value isn't provided")
}

id := idRaw.(string)
externalID := externalIDRaw.(string)

federation := &users.Federation{
ExternalID: externalID,
ID: id,
}

return federation, nil
}

func convertIAMSetToRoles(rolesSet *schema.Set) ([]roles.Role, error) {
rolesList := rolesSet.List()

output := make([]roles.Role, len(rolesList))
var roleNameRaw, scopeRaw, projectIDRaw interface{}

for i := range rolesList {
var roleName, scope, projectID string
resourceRoleMap := rolesList[i].(map[string]interface{})

if roleNameRaw = resourceRoleMap["role_name"]; roleNameRaw == "" {
return nil, errors.New("role_name value isn't provided")
}
if scopeRaw = resourceRoleMap["scope"]; scopeRaw == "" {
return nil, errors.New("scope value isn't provided")
}

roleName = roleNameRaw.(string)
scope = scopeRaw.(string)

if projectIDRaw = resourceRoleMap["project_id"]; projectIDRaw == "" && scope == string(roles.Project) {
return nil, errors.New("project_id must be set for project scope")
} else if projectIDRaw != "" {
if scope != string(roles.Project) {
return nil, errors.New("project_id can be set only for project scope")
}
projectID = projectIDRaw.(string)
}

output[i] = roles.Role{
RoleName: roles.Name(roleName),
Scope: roles.Scope(scope),
ProjectID: projectID,
}
}

return output, nil
}

func convertIAMRolesToSet(roles []roles.Role) []interface{} {
result := make([]interface{}, 0, len(roles))
for _, role := range roles {
result = append(result, map[string]interface{}{
"role_name": role.RoleName,
"scope": role.Scope,
"project_id": role.ProjectID,
})
}

return result
}

func convertIAMFederationToList(federation *users.Federation) []interface{} {
if federation == nil {
return nil
}

return []interface{}{
map[string]interface{}{
"id": federation.ID,
"external_id": federation.ExternalID,
},
}
}
142 changes: 142 additions & 0 deletions selectel/iam_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package selectel

import (
"testing"

"github.com/selectel/iam-go/service/roles"
"github.com/stretchr/testify/assert"
)

func TestIAMDiffRoles(t *testing.T) {
type args struct {
oldRoles []roles.Role
newRoles []roles.Role
}
tests := map[string]struct {
args args
wantToUnassign []roles.Role
wantToAssign []roles.Role
}{
"Test assigning new roles": {
args: args{
oldRoles: []roles.Role{},
newRoles: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
},
},
wantToUnassign: []roles.Role{},
wantToAssign: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
},
},
"Test unassigning all roles": {
args: args{
oldRoles: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
},
newRoles: []roles.Role{},
},
wantToUnassign: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
},
wantToAssign: []roles.Role{},
},
"Test mix of assigning and unassigning roles": {
args: args{
oldRoles: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
},
newRoles: []roles.Role{
{
RoleName: "role2",
Scope: "scope2",
ProjectID: "project2",
},
{
RoleName: "role3",
Scope: "scope3",
ProjectID: "project3",
},
{
RoleName: "role4",
Scope: "scope4",
ProjectID: "project4",
},
},
},
wantToUnassign: []roles.Role{
{
RoleName: "role1",
Scope: "scope1",
ProjectID: "project1",
},
},
wantToAssign: []roles.Role{
{
RoleName: "role3",
Scope: "scope3",
ProjectID: "project3",
},
{
RoleName: "role4",
Scope: "scope4",
ProjectID: "project4",
},
},
},
}

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
actualRolesToUnassign, actualRolesToAssign := diffRoles(tt.args.oldRoles, tt.args.newRoles)
assert := assert.New(t)
assert.Equal(tt.wantToUnassign, actualRolesToUnassign)
assert.Equal(tt.wantToAssign, actualRolesToAssign)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccVPCV2UserImportBasic(t *testing.T) {
resourceName := "selectel_vpc_user_v2.user_tf_acc_test_1"
userName := acctest.RandomWithPrefix("tf-acc")
userPassword := acctest.RandString(8)
func TestAccIAMV1ServiceUserImportBasic(t *testing.T) {
resourceName := "selectel_iam_serviceuser_v1.serviceuser_tf_acc_test_1"
serviceUserName := acctest.RandomWithPrefix("tf-acc")
serviceUserPassword := "A" + acctest.RandString(8) + "1"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccSelectelPreCheck(t) },
ProviderFactories: testAccProviders,
CheckDestroy: testAccCheckVPCV2UserDestroy,
CheckDestroy: testAccCheckIAMV1ServiceUserDestroy,
Steps: []resource.TestStep{
{
Config: testAccVPCV2UserBasic(userName, userPassword),
Config: testAccIAMV1ServiceUserBasic(serviceUserName, serviceUserPassword),
},
{
ResourceName: resourceName,
Expand Down
Loading
Loading