How to use the go-mysql-driver with ssl on aws with a mysql rds instance - mysql

I have a RDS instance running on AWS and I want to know how to connect to that instance over ssl.
From this link Using SSL with mysql database. AWS sets up our database registered with a certificate and provides the root certificate for download.
AWS rds root ca
Now the go-mysql-driver provides this information in there documentation to setup an ssl connection.
rootCertPool := x509.NewCertPool()
pem, err := ioutil.ReadFile("/path/ca-cert.pem")
if err != nil {
log.Fatal(err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
log.Fatal("Failed to append PEM.")
}
clientCert := make([]tls.Certificate, 0, 1)
certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client- key.pem")
if err != nil {
log.Fatal(err)
}
clientCert = append(clientCert, certs)
mysql.RegisterTLSConfig("custom", &tls.Config{
RootCAs: rootCertPool,
Certificates: clientCert,
})
db, err := sql.Open("mysql", "user#tcp(localhost:3306)/test?tls=custom")
The example indicates that I need a client certificate and client key.
But amazon only provides the root certificate. How can I use that with go-mysql-driver to connect to my mysql instance?

I'd add a comment to the previous answer, but my reputation isn't high enough. This is working for me:
rootCertPool := x509.NewCertPool()
pem, err := ioutil.ReadFile("/path/ca-cert.pem")
if err != nil {
log.Fatal(err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
log.Fatal("Failed to append PEM.")
}
mysql.RegisterTLSConfig("custom", &tls.Config{
ServerName: "qcaurora.cb556lynvxio.us-east-1.rds.amazonaws.com",
RootCAs: rootCertPool,
})
db, err := sql.Open("mysql", "user:pass#tcp(qcrds.example.com:3306)/databasename?tls=custom")
The only change from the above is the addition of the ServerName field. I've also clarified the address field for use with a CNAME dns entry and using a password. If you don't use a CNAME to RDS, you could leave out the ServerName field.
I'm using go 1.11 with go-sql-driver/mysql version v1.4.1.

From looking at the docs here and here and here, it looks like you simply need to set the RootCAs value to the root certificate you obtained from AWS. You don't need to set the Certificates value since you aren't using a client cert. So the code would look something like:
rootCertPool := x509.NewCertPool()
pem, err := ioutil.ReadFile("/path/ca-cert.pem")
if err != nil {
log.Fatal(err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
log.Fatal("Failed to append PEM.")
}
mysql.RegisterTLSConfig("custom", &tls.Config{
RootCAs: rootCertPool,
})
db, err := sql.Open("mysql", "user#tcp(localhost:3306)/test?tls=custom")

Related

How to connect MySQL with AWS?

I am trying to connect the MySQL database with AWS RDS but don't have any idea what should be included.
I created the RDS database, got the DB HOST value, and got the region but I don't know how to apply it and make it work.
func Connect() (db *sql.DB) {
db_user := middleware.LoadEnvVariable("DB_USER")
db_password := middleware.LoadEnvVariable("DB_PASSWORD")
db_address := middleware.LoadEnvVariable("DB_ADDRESS")
db_db := middleware.LoadEnvVariable("DB_DB")
s := fmt.Sprintf("%s:%s#tcp(%s:3306)/%s", db_user, db_password, db_address, db_db)
db, err := sql.Open("mysql", s)
if err != nil {
log.Fatal(err)
}
return db
}

How to connect to AWS RDS using Golang?

I am trying to connect to the AWS RDS using the following code. I got help from this website but when I executed this code, it gave me the following error.
Error
panic: failed to create authentication token: failed to refresh cached credentials, no EC2 IMDS role found, operation error ec2imds: GetMetadata, request canceled, context deadline exceeded
Code
func Connect() (db *sql.DB) {
db_user := middleware.LoadEnvVariable("DB_USER")
// db_password := middleware.LoadEnvVariable("DB_PASSWORD")
db_host := "database endpoint string"
db_db := middleware.LoadEnvVariable("DB_DB")
dbEndpoint := fmt.Sprintf("%s:%d", db_address, 3306)
region := "ap-south-1a"
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
panic("configuration error: " + err.Error())
}
authenticationToken, err := auth.BuildAuthToken(context.TODO(), dbEndpoint, region, db_user, cfg.Credentials)
if err != nil {
panic("failed to create authentication token: " + err.Error())
}
s := fmt.Sprintf("%s:%s#tcp(%s)/%s?tls=true&allowCleartextPasswords=true", db_user, authenticationToken, dbEndpoint, db_db)
dbbase, err := sql.Open("mysql", s)
if err != nil {
log.Fatal(err)
}
return dbbase
}

AWS SDK How to increase ECS cluster ec2 instance without auto scaling

I'm using Demon service in ECS Cluster. Demon service cannot use auto-scaling.
I want to increase cluster ec2 instance count via aws ecs sdk.
But I can't find the function doing this.
Is there someone who knows this?
I found solution in aws cli sdk. by changing AsgMaxSize
import "github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients/aws/cloudformation"
...
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
Credentials: credentials.NewStaticCredentials("AKID", "Secret", ""),
})
cloudClient := cloudformation.NewCloudformationClient(&config.CommandConfig{
Session:sess,
})
stackName := "EC2ContainerService-name"
params, err := cloudClient.GetStackParameters(stackName)
if err != nil {
log.Println(err)
return nil
}
log.Println(params)
newParams, err := cloudformation.NewCfnStackParamsForUpdate([]string{"AsgMaxSize"}, params)
if err != nil {
return nil
}
newParams.Add("AsgMaxSize", "3")
out, err := cloudClient.UpdateStack(stackName, newParams)
if err != nil {
log.Println(err)
return nil
}

Golang library (or code) needed for client JSON-RPC2.0 over websocket

I have to add
JSON-RPC2.0
over websockets, to my
Golang
Client process
to communicate with another server. Unfortunately, none of the requirements can be changed.
I have libs and example code that offer parts of the solution but I have been unable to put it all together.
I have looked at Ethereum (I cannot find a client example) Ethereum rpc
A stackoverflow question that dials tcp.
This dials TCP
net.rpc not 2.0, dials tcp
over http net/rpc and http
This one looked promising but I cannot make my client work.
type Params struct {
Name string `json:"name"`
}
func main() {
h := NewRPCHandler()
h.Register("some_handler", dummySuccessHandler)
ts := http.Server{Handler: h}
defer ts.Close()
conn, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8080/ws_rpc", nil)
if err != nil {
log.Printf("Error dialing %v", err)
}
client := jsonrpc.NewClient(conn.UnderlyingConn())
par := &Params{"newuser"}
req, err := json.Marshal(&par)
if err != nil {
log.Printf("Bad marshal %#v", err)
}
var resp Result
err = client.Call("some_handler", &req, &resp)
I tried with/without marshaling but I'm clutching at straws here.

How to create a new MySQL database with go-sql-driver

I'm working on Golang script that automatically clone a database.
I'm using go-sql-driver but i can't find in the documentation a way to create a new database.
Connection to MySQL require an URL scheme like:
user:password#tcp(localhost:3306)/database_name
But the database not exists yet, I just want to connect to the server and then create a new one.
How can I do that? I have to use another driver?
You can perfectly use the go-sql-driver. However, you need to use a mysql user which has the proper access rights to create new databases.
Here is an example:
func create(name string) {
db, err := sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/")
if err != nil {
panic(err)
}
defer db.Close()
_,err = db.Exec("CREATE DATABASE "+name)
if err != nil {
panic(err)
}
_,err = db.Exec("USE "+name)
if err != nil {
panic(err)
}
_,err = db.Exec("CREATE TABLE example ( id integer, data varchar(32) )")
if err != nil {
panic(err)
}
}
Note that the database name is not provided in the connection string. We just create the database after the connection (CREATE DATABASE command), and switch the connection to use it (USE command).
Note: the VividCortex guys maintain a nice database/sql tutorial and documentation at http://go-database-sql.org/index.html
If you want to create a new database if it does not exist, and use it directly in your program, be aware that database/sql maintains a connection pool.
Therefore the opened database connection, should preferably contain the database name. I've seen "Error 1046: No database selected" when database/sql opens a new connection after using db.Exec("USE "+name) manually.
func createAndOpen(name string) *sql.DB {
db, err := sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/")
if err != nil {
panic(err)
}
defer db.Close()
_,err = db.Exec("CREATE DATABASE IF NOT EXISTS "+name)
if err != nil {
panic(err)
}
db.Close()
db, err = sql.Open("mysql", "admin:admin#tcp(127.0.0.1:3306)/" + name)
if err != nil {
panic(err)
}
defer db.Close()
return db
}
My db_config.go file looks like for GO ORM 2.0:
package infrastructure
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm2.0/utils"
)
//Setup Models: initializaing the mysql database
func GetDatabaseInstance() *gorm.DB {
get := utils.GetEnvWithKey
USER := get("DB_USER")
PASS := get("DB_PASS")
HOST := get("DB_HOST")
PORT := get("DB_PORT")
DBNAME := get("DB_NAME")
dsn := fmt.Sprintf("%s:%s#tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", USER, PASS, HOST, PORT, DBNAME)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
_ = db.Exec("CREATE DATABASE IF NOT EXISTS " + DBNAME + ";")
if err != nil {
panic(err.Error())
}
return db
}