github.com/square/finch@v0.0.0-20240412205204-6530c03e2b96/dbconn/mycnf.go (about)

     1  // Copyright 2023 Block, Inc.
     2  
     3  package dbconn
     4  
     5  import (
     6  	"strings"
     7  
     8  	"github.com/go-ini/ini"
     9  
    10  	"github.com/square/finch"
    11  	"github.com/square/finch/config"
    12  )
    13  
    14  // ParseMyCnf parses a MySQL my.cnf file. It only reads the "[client]" section,
    15  // same as the mysql CLI.
    16  func ParseMyCnf(file string) (config.MySQL, error) {
    17  	opts := ini.LoadOptions{AllowBooleanKeys: true}
    18  	mycnf, err := ini.LoadSources(opts, file)
    19  	if err != nil {
    20  		return config.MySQL{}, err
    21  	}
    22  
    23  	cfg := config.MySQL{
    24  		Username: mycnf.Section("client").Key("user").String(),
    25  		Password: mycnf.Section("client").Key("password").String(),
    26  		Hostname: mycnf.Section("client").Key("host").String(),
    27  		Socket:   mycnf.Section("client").Key("socket").String(),
    28  	}
    29  
    30  	port := mycnf.Section("client").Key("port").String()
    31  	if port != "" {
    32  		cfg.Hostname += ":" + port
    33  	}
    34  
    35  	// Translate MySQL ssl-* vars to config.TLS. The vars don't line up
    36  	// perfectly because MySQL has several levels of TLS verification:
    37  	//   https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl-mode
    38  	// But Go tls.Config (which is derived from config.TLS) has only two
    39  	// options: specify tls.Confg.ServerName _or_ .InsecureSkipVerify=true.
    40  	mysqlTLS(file, mycnf, &cfg)
    41  
    42  	finch.Debug("mycnf %s: %s %+v", file, cfg.Redacted())
    43  	return cfg, nil
    44  }
    45  
    46  func mysqlTLS(file string, mycnf *ini.File, cfg *config.MySQL) (tls config.TLS) {
    47  	// USING IMPLICIT RETURN -----------------------------------^
    48  
    49  	tls.MySQLMode = strings.ToUpper(mycnf.Section("client").Key("ssl-mode").String())
    50  	if tls.MySQLMode == "" {
    51  		tls.MySQLMode = "PREFERRED" // MySQL default
    52  	}
    53  
    54  	// Explicitly disabled = not TLS even if other vars set
    55  	if tls.MySQLMode == "DISABLED" {
    56  		finch.Debug("mycnf %s: ssl-mode=DISABLED", file)
    57  		return
    58  	}
    59  
    60  	// As per the MySQL manual:
    61  	// "Connections over Unix socket files are not encrypted with a mode of PREFERRED.
    62  	//  To enforce encryption for Unix socket-file connections, use a mode of REQUIRED or stricter.
    63  	if cfg.Socket != "" && tls.MySQLMode == "PREFERRED" {
    64  		finch.Debug("mycnf %s: ignoring TLS on socket %s", file, cfg.Socket)
    65  		return
    66  	}
    67  
    68  	// Not TLS unless at least 1 of the 3 files is set (no validation yet)
    69  	tls.CA = mycnf.Section("client").Key("ssl-ca").String()
    70  	tls.Cert = mycnf.Section("client").Key("ssl-cert").String()
    71  	tls.Key = mycnf.Section("client").Key("ssl-key").String()
    72  	if !tls.Set() {
    73  		finch.Debug("mycnf %s: TLS not set", file)
    74  		return
    75  	}
    76  
    77  	// Probably legit/normal MySQL TLS config: hostname + at least 1 file.
    78  	// But it's unclear if, for example, PREFERRED = SkipVerify=true?
    79  	return
    80  }