fix: Cred rotation (#20)

* fix: Cred rotation

- fix bug where the rotated service account key was not read. The response needs to be unmarshalled to pull out the values from th fields
- fix bug where the time stamp was not getting updated after rotating credentials
- fix bug where updates without setting a new secret fails
This commit is contained in:
Elim Tsiagbey authored and GitHub committed 2024-11-20 10:22:21 -05:00
1 parent 9acd3acf59
commit baa2c7a2e7
6 files changed
+129 -33

No files matched your search

+17 -11
View File
@@ -88,7 +88,7 @@ func (p *HostPlugin) OnCreateCatalog(ctx context.Context, req *pb.OnCreateCatalo
}
if credState.CredentialsConfig.IsRotatable() && !catalogAttributes.DisableCredentialRotation {
if err := credState.CredentialsConfig.RotateServiceAccountKey(ctx, permissions, p.testGCPClientOpts...); err != nil {
if err := credState.RotateCreds(ctx, permissions, p.testGCPClientOpts...); err != nil {
return nil, err
}
}
@@ -152,12 +152,15 @@ func (p *HostPlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatalo
return nil, status.Errorf(codes.InvalidArgument, "error getting persisted state from proto: %s", err)
}
updatedCredentials, err := credential.GetCredentialsConfig(newCatalog.GetSecrets(), newCatalogAttributes.CredentialAttributes)
if err != nil {
return nil, err
}
// We will be updating credentials when one of two changes occur:
// 1. The new catalog has a service account key, in which case we need to delete the old service account key credentials
// 2. The target service account ID has changed. This indicates a change of credential type to use service account impersonation
if newCatalog.GetSecrets() != nil || newCatalogAttributes.TargetServiceAccountId != oldCatalogAttributes.TargetServiceAccountId {
updatedCredentials, err := credential.GetCredentialsConfig(newCatalog.GetSecrets(), newCatalogAttributes.CredentialAttributes)
if err != nil {
return nil, err
}
if newCatalog.GetSecrets() != nil {
newCredState, err := credential.NewPersistedState([]credential.Option{
credential.WithCredentialsConfig(updatedCredentials),
}...,
@@ -186,11 +189,14 @@ func (p *HostPlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatalo
}
}
if credState.CredentialsConfig.IsRotatable() {
if !updatedCredentials.IsRotatable() && !newCatalogAttributes.DisableCredentialRotation {
return nil, status.Error(codes.InvalidArgument, "cannot rotate credentials for non-rotatable credentials")
}
// This is a validate check to make sure that we aren't trying to
// rotate credentials that are not rotatable. For example,
// Application Default Credentials (ADC) are not rotatable.
if !credState.CredentialsConfig.IsRotatable() && !newCatalogAttributes.DisableCredentialRotation {
return nil, status.Error(codes.InvalidArgument, "cannot rotate credentials for non-rotatable credentials")
}
if credState.CredentialsConfig.IsRotatable() {
// This is a validate check to make sure that we aren't disabling
// rotation for credentials currently being managed by rotation.
// This is not allowed.
@@ -209,7 +215,7 @@ func (p *HostPlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatalo
// If we're enabling rotation now but didn't before, or have
// freshly replaced credentials, we can rotate here.
if !newCatalogAttributes.DisableCredentialRotation && credState.CredsLastRotatedTime.IsZero() {
if err := credState.CredentialsConfig.RotateServiceAccountKey(ctx, permissions, p.testGCPClientOpts...); err != nil {
if err := credState.RotateCreds(ctx, permissions, p.testGCPClientOpts...); err != nil {
return nil, err
}
}
+53
View File
@@ -1172,6 +1172,12 @@ func TestUpdateCatalog(t *testing.T) {
},
},
},
Secrets: &structpb.Struct{
Fields: map[string]*structpb.Value{
cred.ConstPrivateKeyId: structpb.NewStringValue(""),
cred.ConstPrivateKey: structpb.NewStringValue(""),
},
},
},
Persisted: &pb.HostCatalogPersisted{
Secrets: &structpb.Struct{
@@ -1183,8 +1189,55 @@ func TestUpdateCatalog(t *testing.T) {
},
},
},
catalogOpts: []gcpCatalogPersistedStateOption{
withTestInstancesAPIFunc(newTestMockInstances(ctx,
nil,
testMockInstancesWithListInstancesOutput(&computepb.InstanceList{}),
testMockInstancesWithListInstancesError(nil),
)),
},
expectedErr: "cannot rotate credentials for non-rotatable credentials",
},
{
name: "update application default credentials",
req: &pb.OnUpdateCatalogRequest{
CurrentCatalog: &hostcatalogs.HostCatalog{
Attrs: &hostcatalogs.HostCatalog_Attributes{
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
cred.ConstProjectId: structpb.NewStringValue("test-project"),
cred.ConstClientEmail: structpb.NewStringValue("test@example.com"),
cred.ConstZone: structpb.NewStringValue("us-central1-a"),
cred.ConstDisableCredentialRotation: structpb.NewBoolValue(true),
},
},
},
},
NewCatalog: &hostcatalogs.HostCatalog{
Attrs: &hostcatalogs.HostCatalog_Attributes{
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
cred.ConstProjectId: structpb.NewStringValue("test-project-1"),
cred.ConstZone: structpb.NewStringValue("us-central1"),
cred.ConstDisableCredentialRotation: structpb.NewBoolValue(true),
},
},
},
},
},
catalogOpts: []gcpCatalogPersistedStateOption{
withTestInstancesAPIFunc(newTestMockInstances(ctx,
nil,
testMockInstancesWithListInstancesOutput(&computepb.InstanceList{}),
testMockInstancesWithListInstancesError(nil),
)),
},
expectedRsp: &pb.OnUpdateCatalogResponse{
Persisted: &pb.HostCatalogPersisted{
Secrets: &structpb.Struct{},
},
},
},
}
for _, tc := range cases {