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

Save extracted credentials into a secret #775

Merged
merged 7 commits into from
Feb 28, 2018

Conversation

shawn-hurley
Copy link
Contributor

@shawn-hurley shawn-hurley commented Feb 19, 2018

Describe what this PR does and why we need it:
This PR will implement #768
Changes proposed in this pull request

  • Add kubernetes client methods to interact with extracted credentials in the namespace.
  • Add runtime methods for interacting with extracted credentials. These methods should be overridable.
  • Remove all dao implementation and interface methods regarding extracted credentials.
  • Remove all instances of interacting with dao extracted credentials in the broker package. Add back call to APB package to get extracted credentials when needed.
  • Add exposed method on APB that will retrieve the extracted credentials.
  • Update APB package to create/save/delete extracted credentials for the correct actions. this should call the correct runtime package methods.

@openshift-ci-robot openshift-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Feb 19, 2018
Copy link
Contributor

@rthallisey rthallisey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor suggestion

creds, err := runtime.Provider.GetExtractedCredential(id, clusterConfig.Namespace)
if err != nil {
switch {
case err == runtime.ErrCredentialsNotFound:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtime.ErrCredentialsNotFound is extracted credentials were not found
clients.ErrCredentialsNotFound is credentials were not found
apb.ErrExtractedCredentialsNotFound is credentials not found

Maybe instead of using different vars for a similar message, use one variable at the bottom of the call, clients.ErrCredentialsNotFound, and bubble that up to the top level and at each instance that sees the error identify where the error was seen.

// /pkg/apb.go
switch {
case err == runtime.ErrCredentialsNotFound:
                        log.Debugf("APB error: extracted credential secret not found - %v", id)
			return nil, ErrExtractedCredentialsNotFound

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here is my thinking on why each package has its own NotFound Error.

I don't want the error to bleed across package boundaries. Right now runtime package is only called by apb. I think we should keep it that way. The same is not currently true of the client, but eventually, we need to encapsulate the client calls in the runtime package.

I think this allows a user who wants to override the runtime package calls for extracted credentials can send back the runtime error and now our APB package can use that. Does that make sense what I was trying to do?

Would love to hear thoughts on this approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your point about which pkg calling another pkg. That part is fine with me. It just seems silly we have three different vars in three different pkgs saying almost exactly the same thing. A follow up to this could be adding an error pkg with all the error constants.

@@ -94,7 +96,14 @@ func NewRuntime() {
panic(err.Error())
}

Provider = &provider{coe: cluster}
var c ExtractedCredential
if extCreds == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we should have this if/else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if nil we will use the default extracted credentials. This should be in the godoc for the function and will add now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand more what this is now, thanks for the comment.

There's one more thing I want to clear up. How I would create a new ExtractedCredential object without having some understanding of my runtime from the pkg/app/app.go pkg?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to clarify my last comment. The runtime interface is structured so that if you call NewRuntime the Runtime pkg will identify what provider you are using. If we add ExtractedCredential type to the NewRuntime call, pkg/app/app.go needs to know what runtime provider is being used in order to provide a working ExtractedCredential type. The reason for that is because ExtractedCredential is stored in a cluster specific resource, a secret. My point is I don't think we want to pass ExtractedCredential as a param to NewRuntime, rather we should add it behind the runtime interface it be initialized after the NewRuntime call.

Copy link
Contributor Author

@shawn-hurley shawn-hurley Feb 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkg/app/app.go needs to know what runtime provider is being used in order to provide a working ExtractedCredential type. The reason for that is because ExtractedCredential is stored in a cluster-specific resource, a secret

This would certainly be a problem if we had more then k8s as a provider. Currently, we don't and even the CreateSandbox... functions relay on core k8s clients and not the provider. I don't think this is a problem currently. We are tracking a better way to override and change the runtime, which I agree we should do. But this needs to be overridable by anyone who is vendoring the project and wants to change this behavior.

Updating this to show what I mean by just using core k8s client is backed into every provider regardless of the cluster specific type.

https://github.com/openshift/ansible-service-broker/blob/master/pkg/runtime/runtime.go#L150

The sandbox will only ever use k8s client, because we only support k8s and openshift. Because of this I think it is currently a valid assumption that anything that can be done with just k8s will be supported in both the clusters that we currently support. The default extracted credentials does that.

@eriknelson
Copy link
Contributor

eriknelson commented Feb 21, 2018

Caught up with @shawn-hurley to coordinate this PR and #773 since they're in direct conflict. Plan is to bring in #773 first and then rework this PR on top of it. Coming back to review this afterwards.

@eriknelson eriknelson added the 3.10 | release-1.2 Kubernetes 1.10 | Openshift 3.10 | Broker release-1.2 label Feb 21, 2018
@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 21, 2018
@openshift-ci-robot openshift-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Feb 21, 2018
@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 21, 2018
Copy link
Contributor

@rthallisey rthallisey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spoke with Shawn, in order to get the behavior we want here we're going to need to rework the runtime pkg. There's an issue to track this. In the meantime, we'll add a param to NewRuntime to allow this override.

@shawn-hurley shawn-hurley mentioned this pull request Feb 26, 2018
@@ -20,7 +18,7 @@ metadata:
<labels provided>
```

[Gob encoding](https://godoc.org/encoding/gob) will allow us to save arbitrary data in the secret for a key. The secrets keys will look rational to a user who looks at the created secret. This user would need permissions to see the secret, but if someone is looking at the secret making it obvious what data is in there will be helpful.
To encode the credentials in a generic way, we must marshal a `map[string]interface{}` so that we can retrieve the data. This is not how I wanted the secret to look, but will allow anyone to use the credentials and will allow us to retrieve the credentials without writing our own gob parser.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@@ -84,6 +84,13 @@ func (e *executor) Bind(
return
}

labels := map[string]string{"apbAction": "bind", "apbName": instance.Spec.FQName}
err = runtime.Provider.CreateExtractedCredential(bindingID, clusterConfig.Namespace, creds.Credentials, labels)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bind.go change looks good.

if err != nil {
log.Errorf("unable to delete the extracted credentials - %v", err)
e.actionFinishedWithError(err)
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't there some issue that @eriknelson was recently looking at about deleting extracted credentials that might not exist? Will this re-introduce that problem?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it will, think this is where it might make sense for us to have our own error type, and skip the action finished call. Log with INFO level.

Bind(instance *ServiceInstance, parameters *Parameters) <-chan StatusMessage
Unbind(instance *ServiceInstance, parameters *Parameters) <-chan StatusMessage
Bind(instance *ServiceInstance, parameters *Parameters, bindingID string) <-chan StatusMessage
Unbind(instance *ServiceInstance, parameters *Parameters, bindingID string) <-chan StatusMessage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, acceptable to add bindingID

// Please use this method with caution.
func SetExtractedCredentials(id string, creds *ExtractedCredentials) error {
return runtime.Provider.CreateExtractedCredential(id, clusterConfig.Namespace, creds.Credentials, nil)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 ext_creds.go looks good.

@@ -257,7 +257,7 @@ func CreateApp() App {
// Intiialize the cluster config.
apb.InitializeClusterConfig(app.config.GetSubConfig("openshift"))
if app.broker, err = broker.NewAnsibleBroker(
app.dao, app.registry, *app.engine, app.config.GetSubConfig("broker"),
app.dao, app.registry, *app.engine, app.config.GetSubConfig("broker"), app.config.GetString("openshift.namespace"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 app.go

}

// NewAnsibleBroker - Creates a new ansible broker
func NewAnsibleBroker(dao dao.Dao,
registry []registries.Registry,
engine WorkEngine,
brokerConfig *config.Config) (*AnsibleBroker, error) {
brokerConfig *config.Config,
namespace string) (*AnsibleBroker, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's very erik of you 😆

bindExtCreds, err := a.dao.GetExtractedCredentials(bindInstance.ID.String())
if err != nil && !client.IsKeyNotFound(err) {
bindExtCreds, err := apb.GetExtractedCredentials(bindInstance.ID.String())
if err != nil && err != apb.ErrExtractedCredentialsNotFound {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 broker.go looks good

return err
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 client/kubernetes.go looks good

Copy link
Contributor

@eriknelson eriknelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the item that @jmrodri mentioned in deprovision and unbind. Otherwise, looking good.

@@ -41,6 +42,11 @@ const (
GatherCredentialsCommand = "broker-bind-creds"
)

var (
// ErrExtractedCredentialsNotFound - Extracted Credentials are not found.
ErrExtractedCredentialsNotFound = fmt.Errorf("credentials not found")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -70,6 +70,13 @@ func (e *executor) Unbind(
e.actionFinishedWithError(err)
return
}
// Delete the binding extracted credential here.
err = runtime.Provider.DeleteExtractedCredential(bindingID, clusterConfig.Namespace)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might want to just log this at an info level if it's a miss error instead of finishing with error here too.

Copy link
Contributor

@eriknelson eriknelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing:

[2018-02-27T19:10:33.086Z] [DEBUG] - executor::actionFinishedWithSuccess
[2018-02-27T19:10:33.086Z] [WARNING] - executor::actionFinishedWithSuccess was called, but the statusChan was already closed!

During what should be a failed provision.

Test:

  • Create new project and provision mediawiki in that project with admin/admin as the password. This is expected to hard fail because it does not accept the same vals.

We shouldn't be seeing success called in this case.

@shawn-hurley
Copy link
Contributor Author

@eriknelson I have updated and tested based on our quick conversation.

@eriknelson
Copy link
Contributor

@shawn-hurley cool, will test again this morning.

@eriknelson eriknelson merged commit ff1f14a into openshift:master Feb 28, 2018
@eriknelson eriknelson deleted the save-extcreds-secret branch February 28, 2018 16:26
jianzhangbjz pushed a commit to jianzhangbjz/ansible-service-broker that referenced this pull request May 17, 2018
* initial commit

* Fixing marshal and unmarshal of data.

* fixing binding

* adding documentation for creating a new runtime.

* fixing provision issue when no extracted credentials occurs.

* fix for unbind.go

* move action hooks to base methods for provision and update.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 | release-1.2 Kubernetes 1.10 | Openshift 3.10 | Broker release-1.2 needs-review size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants