Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/postgresqlAWSExporter
/postgresql_*.ptar
*.local.json
/vendor
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,11 @@ restored roles will have no password set.
| `pg_bin_dir` | — | Directory containing the PostgreSQL client binaries (`pg_dump`, `pg_dumpall`, `psql`). When omitted, binaries are resolved via `$PATH`. Useful when multiple PostgreSQL versions are installed. |
| `ssl_mode` | `prefer` | SSL mode: `disable`, `allow`, `prefer`, `require`, `verify-ca`, or `verify-full`. Passed via `PGSSLMODE`. |
| `ssl_cert` | — | Path to the client SSL certificate file (PEM). Passed via `PGSSLCERT`. |
| `ssl_cert_data` | — | Inline PEM content of the client SSL certificate. Alternative to `ssl_cert`. |
| `ssl_key` | — | Path to the client SSL private key file (PEM). Passed via `PGSSLKEY`. |
| `ssl_key_data` | — | Inline PEM content of the client SSL private key. Alternative to `ssl_key`. |
| `ssl_root_cert` | — | Path to the root CA certificate used to verify the server (PEM). Passed via `PGSSLROOTCERT`. |
| `ssl_root_cert_data` | — | Inline PEM content of the root CA certificate. Alternative to `ssl_root_cert`. |

### Exporter options (`postgres://`)

Expand All @@ -119,8 +122,11 @@ restored roles will have no password set.
| `pg_bin_dir` | — | Directory containing the PostgreSQL client binaries (`pg_restore`, `psql`). When omitted, binaries are resolved via `$PATH`. Useful when multiple PostgreSQL versions are installed. |
| `ssl_mode` | `prefer` | SSL mode: `disable`, `allow`, `prefer`, `require`, `verify-ca`, or `verify-full`. Passed via `PGSSLMODE`. |
| `ssl_cert` | — | Path to the client SSL certificate file (PEM). Passed via `PGSSLCERT`. |
| `ssl_cert_data` | — | Inline PEM content of the client SSL certificate. Alternative to `ssl_cert`. |
| `ssl_key` | — | Path to the client SSL private key file (PEM). Passed via `PGSSLKEY`. |
| `ssl_key_data` | — | Inline PEM content of the client SSL private key. Alternative to `ssl_key`. |
| `ssl_root_cert` | — | Path to the root CA certificate used to verify the server (PEM). Passed via `PGSSLROOTCERT`. |
| `ssl_root_cert_data` | — | Inline PEM content of the root CA certificate. Alternative to `ssl_root_cert`. |

### Examples

Expand Down Expand Up @@ -301,8 +307,11 @@ functions (execution role).
| `pg_bin_dir` | — | Directory containing the PostgreSQL client binaries. When omitted, binaries are resolved via `$PATH`. |
| `ssl_mode` | `prefer` | SSL mode. IAM authentication requires an encrypted connection — use `require` or higher. |
| `ssl_cert` | — | Path to the client SSL certificate file (PEM). Passed via `PGSSLCERT`. |
| `ssl_cert_data` | — | Inline PEM content of the client SSL certificate. Alternative to `ssl_cert`. |
| `ssl_key` | — | Path to the client SSL private key file (PEM). Passed via `PGSSLKEY`. |
| `ssl_key_data` | — | Inline PEM content of the client SSL private key. Alternative to `ssl_key`. |
| `ssl_root_cert` | — | Path to the root CA certificate used to verify the server (PEM). Passed via `PGSSLROOTCERT`. |
| `ssl_root_cert_data` | — | Inline PEM content of the root CA certificate. Alternative to `ssl_root_cert`. |

### Importer examples

Expand Down Expand Up @@ -343,8 +352,11 @@ the password for the restore connection.
| `pg_bin_dir` | — | Directory containing the PostgreSQL client binaries. When omitted, binaries are resolved via `$PATH`. |
| `ssl_mode` | `prefer` | SSL mode. IAM authentication requires an encrypted connection — use `require` or higher. |
| `ssl_cert` | — | Path to the client SSL certificate file (PEM). Passed via `PGSSLCERT`. |
| `ssl_cert_data` | — | Inline PEM content of the client SSL certificate. Alternative to `ssl_cert`. |
| `ssl_key` | — | Path to the client SSL private key file (PEM). Passed via `PGSSLKEY`. |
| `ssl_key_data` | — | Inline PEM content of the client SSL private key. Alternative to `ssl_key`. |
| `ssl_root_cert` | — | Path to the root CA certificate used to verify the server (PEM). Passed via `PGSSLROOTCERT`. |
| `ssl_root_cert_data` | — | Inline PEM content of the root CA certificate. Alternative to `ssl_root_cert`. |

### Exporter examples

Expand Down Expand Up @@ -430,8 +442,11 @@ The PostgreSQL server must have:
| `pg_bin_dir` | — | Directory containing the PostgreSQL client binaries (`pg_basebackup`, `psql`). When omitted, binaries are resolved via `$PATH`. Useful when multiple PostgreSQL versions are installed. |
| `ssl_mode` | `prefer` | SSL mode: `disable`, `allow`, `prefer`, `require`, `verify-ca`, or `verify-full`. Passed via `PGSSLMODE`. |
| `ssl_cert` | — | Path to the client SSL certificate file (PEM). Passed via `PGSSLCERT`. |
| `ssl_cert_data` | — | Inline PEM content of the client SSL certificate. Alternative to `ssl_cert`. |
| `ssl_key` | — | Path to the client SSL private key file (PEM). Passed via `PGSSLKEY`. |
| `ssl_key_data` | — | Inline PEM content of the client SSL private key. Alternative to `ssl_key`. |
| `ssl_root_cert` | — | Path to the root CA certificate used to verify the server (PEM). Passed via `PGSSLROOTCERT`. |
| `ssl_root_cert_data` | — | Inline PEM content of the root CA certificate. Alternative to `ssl_root_cert`. |

### Restoring a physical backup

Expand Down
15 changes: 15 additions & 0 deletions awsexporter/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,30 @@
"minLength": 1,
"description": "Path to the client SSL certificate file (PEM format), passed via PGSSLCERT."
},
"ssl_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL certificate. Alternative to ssl_cert."
},
"ssl_key": {
"type": "string",
"minLength": 1,
"description": "Path to the client SSL private key file (PEM format), passed via PGSSLKEY."
},
"ssl_key_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL private key. Alternative to ssl_key."
},
"ssl_root_cert": {
"type": "string",
"minLength": 1,
"description": "Path to the root CA certificate used to verify the server (PEM format), passed via PGSSLROOTCERT."
},
"ssl_root_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the root CA certificate. Alternative to ssl_root_cert."
}
}
}
15 changes: 15 additions & 0 deletions awsimporter/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,30 @@
"minLength": 1,
"description": "Path to the client SSL certificate file (PEM format), passed via PGSSLCERT."
},
"ssl_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL certificate. Alternative to ssl_cert."
},
"ssl_key": {
"type": "string",
"minLength": 1,
"description": "Path to the client SSL private key file (PEM format), passed via PGSSLKEY."
},
"ssl_key_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL private key. Alternative to ssl_key."
},
"ssl_root_cert": {
"type": "string",
"minLength": 1,
"description": "Path to the root CA certificate used to verify the server (PEM format), passed via PGSSLROOTCERT."
},
"ssl_root_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the root CA certificate. Alternative to ssl_root_cert."
}
}
}
5 changes: 4 additions & 1 deletion binimporter/importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ func (p *BinImporter) Ping(ctx context.Context) error {
return p.conn.Ping(ctx, "")
}

func (p *BinImporter) Close(ctx context.Context) error { return nil }
func (p *BinImporter) Close(ctx context.Context) error {
p.conn.Cleanup()
return nil
}
func (p *BinImporter) Root() string { return "/" }
func (p *BinImporter) Origin() string { return p.conn.Host }
func (p *BinImporter) Type() string { return "postgres+bin" }
Expand Down
15 changes: 15 additions & 0 deletions binimporter/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,30 @@
"minLength": 1,
"description": "Path to the client SSL certificate file (PEM format), passed via PGSSLCERT."
},
"ssl_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL certificate. Alternative to ssl_cert."
},
"ssl_key": {
"type": "string",
"minLength": 1,
"description": "Path to the client SSL private key file (PEM format), passed via PGSSLKEY."
},
"ssl_key_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL private key. Alternative to ssl_key."
},
"ssl_root_cert": {
"type": "string",
"minLength": 1,
"description": "Path to the root CA certificate used to verify the server (PEM format), passed via PGSSLROOTCERT."
},
"ssl_root_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the root CA certificate. Alternative to ssl_root_cert."
}
}
}
1 change: 1 addition & 0 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (p *Exporter) Ping(ctx context.Context) error {
}

func (p *Exporter) Close(ctx context.Context) error {
p.conn.Cleanup()
return nil
}

Expand Down
15 changes: 15 additions & 0 deletions exporter/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,30 @@
"minLength": 1,
"description": "Path to the client SSL certificate file (PEM format), passed via PGSSLCERT."
},
"ssl_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL certificate. Alternative to ssl_cert."
},
"ssl_key": {
"type": "string",
"minLength": 1,
"description": "Path to the client SSL private key file (PEM format), passed via PGSSLKEY."
},
"ssl_key_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL private key. Alternative to ssl_key."
},
"ssl_root_cert": {
"type": "string",
"minLength": 1,
"description": "Path to the root CA certificate used to verify the server (PEM format), passed via PGSSLROOTCERT."
},
"ssl_root_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the root CA certificate. Alternative to ssl_root_cert."
}
}
}
5 changes: 4 additions & 1 deletion importer/importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,10 @@ func (p *Importer) Ping(ctx context.Context) error {
return p.conn.Ping(ctx, p.database)
}

func (p *Importer) Close(ctx context.Context) error { return nil }
func (p *Importer) Close(ctx context.Context) error {
p.conn.Cleanup()
return nil
}
func (p *Importer) Root() string { return "/" }
func (p *Importer) Origin() string { return p.conn.Host }
func (p *Importer) Type() string { return p.connType }
Expand Down
15 changes: 15 additions & 0 deletions importer/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,30 @@
"minLength": 1,
"description": "Path to the client SSL certificate file (PEM format), passed via PGSSLCERT."
},
"ssl_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL certificate. Alternative to ssl_cert."
},
"ssl_key": {
"type": "string",
"minLength": 1,
"description": "Path to the client SSL private key file (PEM format), passed via PGSSLKEY."
},
"ssl_key_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the client SSL private key. Alternative to ssl_key."
},
"ssl_root_cert": {
"type": "string",
"minLength": 1,
"description": "Path to the root CA certificate used to verify the server (PEM format), passed via PGSSLROOTCERT."
},
"ssl_root_cert_data": {
"type": "string",
"minLength": 1,
"description": "Inline PEM content of the root CA certificate. Alternative to ssl_root_cert."
}
}
}
63 changes: 55 additions & 8 deletions pgconn/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ import (
_ "github.com/jackc/pgx/v5/stdlib"
)

// sslFileParam describes one SSL file parameter and its inline-content variant.
type sslFileParam struct {
pathKey string // config key for the file path, e.g. "ssl_cert"
dataKey string // config key for inline content, e.g. "ssl_cert_data"
field *string // pointer to the ConnConfig field to set
}

// writeTempFile writes content to a temporary PEM file and returns its path.
func writeTempFile(label, content string) (string, error) {
f, err := os.CreateTemp("", "plakar-pg-"+label+"-*")
if err != nil {
return "", fmt.Errorf("%s_data: create temp file: %w", label, err)
}
defer f.Close()
if _, err := f.WriteString(content); err != nil {
_ = os.Remove(f.Name())
return "", fmt.Errorf("%s_data: write temp file: %w", label, err)
}
return f.Name(), nil
}


// ConnConfig holds the connection parameters shared by all PostgreSQL connectors.
type ConnConfig struct {
Host string
Expand All @@ -21,6 +43,17 @@ type ConnConfig struct {
SSLCert string // path to client certificate file (PEM)
SSLKey string // path to client private key file (PEM)
SSLRootCert string // path to root CA certificate file (PEM)

tmpFiles []string // temp files written for inline SSL content; removed by Cleanup
}

// Cleanup removes any temporary files that were created for inline SSL content.
// It should be called when the connector is closed.
func (c *ConnConfig) Cleanup() {
for _, f := range c.tmpFiles {
_ = os.Remove(f)
}
c.tmpFiles = nil
}

// ParseConnConfig parses host, port, username, and password from the "location"
Expand Down Expand Up @@ -79,14 +112,28 @@ func ParseConnConfig(config map[string]string) (ConnConfig, string, error) {
return ConnConfig{}, "", fmt.Errorf("ssl_mode: invalid value %q (accepted: disable, allow, prefer, require, verify-ca, verify-full)", v)
}
}
if v, ok := config["ssl_cert"]; ok && v != "" {
c.SSLCert = v
}
if v, ok := config["ssl_key"]; ok && v != "" {
c.SSLKey = v
}
if v, ok := config["ssl_root_cert"]; ok && v != "" {
c.SSLRootCert = v
for _, p := range []sslFileParam{
{"ssl_cert", "ssl_cert_data", &c.SSLCert},
{"ssl_key", "ssl_key_data", &c.SSLKey},
{"ssl_root_cert", "ssl_root_cert_data", &c.SSLRootCert},
} {
path, hasPath := config[p.pathKey]
data, hasData := config[p.dataKey]
if hasPath && path != "" && hasData && data != "" {
c.Cleanup()
return ConnConfig{}, "", fmt.Errorf("%s and %s are mutually exclusive", p.pathKey, p.dataKey)
}
if hasPath && path != "" {
*p.field = path
} else if hasData && data != "" {
tmp, err := writeTempFile(p.pathKey, data)
if err != nil {
c.Cleanup()
return ConnConfig{}, "", err
}
*p.field = tmp
c.tmpFiles = append(c.tmpFiles, tmp)
}
}

return c, dbPath, nil
Expand Down
Loading
Loading