Permissions error when trying to connect GCP SQL Database with Golang cloud sql proxy package - go

I'm trying to connect my go app on my VM (Debain 9) server to my mysql database using the package: github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql
Looking at connection function:
// Cfg returns the effective *mysql.Config to represent connectivity to the
// provided instance via the given user and password. The config can be
// modified and passed to DialCfg to connect. If you don't modify the returned
// config before dialing, consider using Dial or DialPassword.
func Cfg(instance, user, password string) *mysql.Config {
I assume I put in the instance 'Instance connection name that is found on the GCP instance connection database page:
`
package main
import (
"fmt"
"os"
"github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql"
)
func main() {
cfg := mysql.Cfg("MyAccount:us-west2:myDatabase", "root", os.Getenv("GCPDBPass"))
db, err := mysql.DialCfg(cfg)
if err != nil {
panic(err)
}
fmt.Print(db)
}
Where I find my instance connection name
I get an error:
panic: ensure that the account has access to "MyAccount" (and make sure there's no typo in that name)
I've hooked up the VM instance IP to the Authorized networks in the Database so I don't know if I'm using the correct instance or user with this package.

In my case the issue was because of the lower version of the "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql" package. Upgrading the package using the command go get -v -u github.com/GoogleCloudPlatform/cloudsql-proxy resolved the issue. Below is the code snippet
"database/sql"
_ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/mysql"
connString := "user:password#cloudsql(project_id:region:instance)/dbname?charset=utf8&parseTime=True&loc=Local"
db, err := sql.Open("mysql", connectionString)

Related

MSAL Golang how to get user profile

I am trying to integrate my Golang app with Azure using MSAL. I created Azure app and I wrote sample code to create public client . Below code worked.
package main
import (
"fmt"
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
)
func main() {
publicClientApp, err := public.New("client_id", public.WithAuthority("https://login.microsoftonline.com/Enter_The_Tenant_Name_Here"))
if err != nil {
panic(err)
}
fmt.Println(publicClientApp)
}
I would like to know how I can use this publicClientApp to get user profile. I could not find anything much in MSAL documentation
I used Microsoft graph API to get the profile.

How to set broker.SubscriberOptions in go-micro

I am trying to configure a RabbitMQ broker using the go-micro framework. I have noticed that the broker interface in go-micro has a broker.SubscriberOptions struct which allows configuring the parameters I am looking for (AutoAck, Queue name and so on) however I am unable to figure out how to pass this when starting a broker.
This is how a simple rabbit go-micro setup would look like
package main
import (
"log"
"github.com/micro/go-micro/server"
"github.com/micro/go-plugins/broker/rabbitmq"
micro "github.com/micro/go-micro"
)
func main() {
// Create a new service. Optionally include some options here.
service := micro.NewService(
micro.Name("go-micro-rabbit"),
micro.Broker(rabbitmq.NewBroker()),
)
// Init will parse the command line flags.
service.Init()
// Register handler
proto.RegisterGreeterHandler(service.Server(), new(Greeter))
micro.RegisterSubscriber("micro-exchange", service.Server(), myFunc, server.SubscriberQueue("my-queue"))
// Run the server
if err := service.Run(); err != nil {
log.Fatal(err)
}
}
The micro.RegisterSubscriber method takes in a list of server.SubscriberOption but does not allow me to set the broker.SubscriberOptions and the rabbitmq.NewBroker allows setting broker.Options but once again, not broker.SubscriberOptions
I have dug in the code of go-micro but have been unable to figure out how the broker.Subscribe method (Which exposes the correct struct) is called or by who.
Is this possible at all? Is it maybe something not yet fully fleshed out in the API?

Dependency Injection & Testing

I'm working on a small Go application that's basically a wrapper for various password stores (Ansible Vault, Hashicorp Vault, Chef Vault, etc). The idea is: In my various provisioning scripts, I can use my Go wrapper to grab secrets and if we decide to switch password stores behind the scenes, all of the interfaces don't need to be updated across my projects.
I'm trying to setup proper tests for this application, and in doing so, am trying to figure out the best way to to inject my dependencies.
For example, lets say the project is called secrets. And one of my implementations is ansible. And the ansible implementation needs its own parser and needs to open its own connection to the ansible vault, to retrieve the data.
So I might have the following:
package secrets
type PasswordStore interface {
GetKey(key string) (string, error)
}
func New(backend string, config map[string]interface{}) (PasswordStore, error) {
switch backend {
case "ansible":
return ansible.New(config)
default:
return nil, fmt.Errorf("Password store '%s' not supported.", backend)
}
}
package ansible
type Connection interface {
open() (string, error)
}
type Ansible struct {
connection Connection
contents map[string]string
}
func New(c map[string]interface{}) (*Ansible, error) {
conn, err := NewConnection(c["ansible_path"].(string))
if err != nil {
return nil, err
}
// open connection, parse, etc...
a := &Ansible{
connection: conn,
contents: parsedData,
}
return a, nil
}
So this seems nice because the secrets package doesn't need knowledge of the ansible package dependencies (connection), and the factory just new's up the instance with some config data. However, if I need to mock the connection that Ansible receives, there doesn't seem to be a good way to do this (unless that config map had a connection option called mock)
The other option is to abandon the factory, and just assemble all the dependencies from the secrets package, like:
package secrets
type PasswordStore interface {
GetKey(key string) (string, error)
}
func New(backend string, config map[string]interface{}) (PasswordStore, error) {
switch backend {
case "ansible":
return ansible.New(AnsibleConnection{}, config)
default:
return nil, fmt.Errorf("Password store '%s' not supported.", backend)
}
}
package ansible
// same as before in this file, but with injected dependency ...
func New(connect Connection, c map[string]interface{}) (*Ansible, error) {
conn, err := connect.NewConnection(c["ansible_path"].(string))
if err != nil {
return nil, err
}
// open connection, parse, etc...
a := &Ansible{
connection: conn,
contents: parsedData,
}
return a, nil
}
Now the dependency is injected, but it seems like secrets needs to have knowledge of every dependency for every implementation.
Is there a more logical way to structure this so that secrets knows less? Or is it typical for the top level package to be orchestrating everything?
What decides what the backend is? That should help guide you. I've done something similar with support for multiple databases on a project, and what I did was basically:
config package reads in config file, which determines what backend is being used
store package offers the generic interface and has a function that takes a config, and returns an implementation
server package references only the interface
main package reads the config, passes it to the factory function in store, then injects the result into the server on creation
So when I create my server (which actually uses the data store), I pass the config to the factory function in store, which returns an interface, and then inject that into the server. The only thing that has to know about the different concrete implementations is the same package that exposes the interface and factory; the server, config, and main packages see it as a black box.

How do I change the import file?

I have the following function in golang:
import (
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/aws/session"
"fmt"
)
func NewIAM() *SphinxIAM {
// awsConfig := aws.NewConfig()
sess, err := session.NewSession()
if err != nil {
fmt.Println("Failed to create session,", err)
return nil
}
session := &SphinxIAM{iam: iam.New(sess)}
return session
}
Now, I am getting the following error when I run this:
cannot use sess (type *session.Session) as type "github.com/aws/aws-sdk-go/aws/client".ConfigProvider in argument to iam.New:
*session.Session does not implement "github.com/aws/aws-sdk-go/aws/client".ConfigProvider (wrong type for ClientConfig method)
have ClientConfig(string, ...*"stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws".Config) "stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws/client".Config
want ClientConfig(string, ...*"github.com/aws/aws-sdk-go/aws".Config) "github.com/aws/aws-sdk-go/aws/client".Config
I have to change the method getting imported but how do I exactly do that?
Thanks!
The problem here is that your github.com/aws/aws-sdk-go/aws/session package is vendored, it is loaded from the folder stash/cloud/sphinx/vendor/github.com/aws/aws-sdk-go/aws.
But the function you want to pass it: iam.New() is not vendored, it does not come from the same vendor folder (stash/cloud/sphinx/vendor/xxx) but it comes directly from github.com/aws/aws-sdk-go/service/iam.
Either put both packages under the same vendor folder, or none. It is possible that one of your dependency tool does this, (e.g. glide), in which case you should instruct your tool to handle both as vendored.

Google Cloud Bigtable authentication with Go

I'm trying to insert a simple record as in GoDoc. But this returns,
rpc error: code = 7 desc = "User can't access project: tidy-groove"
When I searched for grpc codes, it says..
PermissionDenied Code = 7
// Unauthenticated indicates the request does not have valid
// authentication credentials for the operation.
I've enabled Big table in my console and created a cluster and a service account and recieved the json. What I'm doing wrong here?
package main
import (
"fmt"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
"google.golang.org/cloud"
"google.golang.org/cloud/bigtable"
"io/ioutil"
)
func main() {
fmt.Println("Start!")
put()
}
func getClient() *bigtable.Client {
jsonKey, err := ioutil.ReadFile("TestProject-7854ea9op741.json")
if err != nil {
fmt.Println(err.Error())
}
config, err := google.JWTConfigFromJSON(
jsonKey,
bigtable.Scope,
) // or bigtable.AdminScope, etc.
if err != nil {
fmt.Println(err.Error())
}
ctx := context.Background()
client, err := bigtable.NewClient(ctx, "tidy-groove", "asia-east1-b", "test1-bigtable", cloud.WithTokenSource(config.TokenSource(ctx)))
if err != nil {
fmt.Println(err.Error())
}
return client
}
func put() {
ctx := context.Background()
client := getClient()
tbl := client.Open("table1")
mut := bigtable.NewMutation()
mut.Set("links", "maps.google.com", bigtable.Now(), []byte("1"))
mut.Set("links", "golang.org", bigtable.Now(), []byte("1"))
err := tbl.Apply(ctx, "com.google.cloud", mut)
if err != nil {
fmt.Println(err.Error())
}
}
I've solved the problem. It's nothing wrong with the code, but config json itself. So anyone who out there want to authenticate and came here by google search... This code is correct and working perfectly. What I've done wrong is follows.
First I made a service account and got the json. But google warned me that im not an owner of project hence it wont be added to accept list but anyway it let me download the json.
Then I deleted that key from console and requested project owner to create a key for me.
There he has created another key with the same name I given.. And since he's the owner no error/warning msgs displayed and successfully json file was downloaded.
When I tried with that... my question begun. That's when i posted this question.
After that with no solutions. I asked owner to delete that key and create another key but with a different name..
Then it worked! It seems if you try to create a key with non-owner account and then again create with same name ( after deleting original of course ) has no effect. Hope this helps everyone out there :)
Take a look at: helloworld.go or search.go which uses GOOGLE_APPLICATION_CREDENTIALS environment variable.
For most environments, you no longer even need to set GOOGLE_APPLICATION_CREDENTIALS. Google Cloud Platform, Managed VMs or Google App Engine all have the right thing set for you. Your desktop environment will also be correct if you've used gcloud init or it's predecessor gcloud auth login followed by gcloud config set project <projectID>.

Resources