Skip to content

Commit 639c569

Browse files
committed
Implement client configs
Signed-off-by: Jan-Otto Kröpke <[email protected]>
1 parent b9bba17 commit 639c569

30 files changed

+368
-736
lines changed

cmd/daemon/root.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"flag"
77
"fmt"
88
"io"
9+
"io/fs"
910
"log/slog"
1011
"net/http"
1112
"net/http/pprof"
@@ -74,16 +75,21 @@ func Execute(args []string, logWriter io.Writer, version, commit, date string) i
7475
return 1
7576
}
7677

77-
openvpnClient := openvpn.New(logger, conf)
78+
var ccdFS fs.FS
79+
if conf.OpenVpn.CCD.Enabled {
80+
ccdFS = os.DirFS(conf.OpenVpn.CCD.Path)
81+
}
82+
83+
openVPNClient := openvpn.New(logger, conf, ccdFS)
7884

79-
oAuth2Client, err := oauth2.New(ctx, logger, conf, httpClient, tokenStorage, provider, openvpnClient)
85+
oAuth2Client, err := oauth2.New(ctx, logger, conf, httpClient, tokenStorage, provider, openVPNClient)
8086
if err != nil {
8187
logger.Error(err.Error())
8288

8389
return 1
8490
}
8591

86-
openvpnClient.SetOAuth2Client(oAuth2Client)
92+
openVPNClient.SetOAuth2Client(oAuth2Client)
8793

8894
httpHandler, err := httphandler.New(conf, oAuth2Client)
8995
if err != nil {
@@ -126,7 +132,7 @@ func Execute(args []string, logWriter io.Writer, version, commit, date string) i
126132
go func() {
127133
defer wg.Done()
128134

129-
if err := openvpnClient.Connect(context.Background()); err != nil {
135+
if err := openVPNClient.Connect(context.Background()); err != nil {
130136
cancel(fmt.Errorf("openvpn: %w", err))
131137

132138
return

docs/Client specific configuration.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Client specific configuration
2+
3+
## Introduction
4+
5+
This document describes the client specific configuration options of openvpn-auth-oauth2.
6+
It mimics the client-config-dir functionality of OpenVPN, but instead the client username, a token claim is
7+
used as config identifier.
8+
9+
## Configuration

docs/Configuration.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ openvpn:
7878
# common-names:
7979
# - "test"
8080
# - "test2"
81+
ccd:
82+
enabled: false
83+
token-claim: ""
84+
path: "/etc/openvpn-auth-oauth2/"
8185
common-name:
8286
environment-variable-name: common_name
8387
mode: plain
@@ -95,9 +99,10 @@ openvpn:
9599

96100
<!-- BEGIN USAGE -->
97101
```
98-
Usage of openvpn-auth-oauth2:
99102
Documentation available at https://github.com/jkroepke/openvpn-auth-oauth2/wiki
100103
104+
Usage of ./openvpn-auth-oauth2:
105+
101106
--config string
102107
path to one .yaml config file (env: CONFIG_CONFIG)
103108
--debug.listen string
@@ -186,6 +191,12 @@ Documentation available at https://github.com/jkroepke/openvpn-auth-oauth2/wiki
186191
Override the username of a session with the username from the token by using auth-token-user, if the client username is empty (env: CONFIG_OPENVPN_AUTH__TOKEN__USER) (default true)
187192
--openvpn.bypass.common-names value
188193
bypass oauth authentication for CNs. Comma separated list. (env: CONFIG_OPENVPN_BYPASS_COMMON__NAMES)
194+
--openvpn.ccd.enabled
195+
If true, openvpn-auth-oauth2 will read the CCD directory for additional configuration. This function mimic the client-config-dir directive in OpenVPN. (env: CONFIG_OPENVPN_CCD_ENABLED)
196+
--openvpn.ccd.path string
197+
Path to the CCD directory. openvpn-auth-oauth2 will look for an file with an .conf suffix and returns the content back. (env: CONFIG_OPENVPN_CCD_PATH) (default "/etc/openvpn-auth-oauth2/ccd/")
198+
--openvpn.ccd.token-claim string
199+
If non-empty, the value of the token claim is used to lookup the configuration file in the CCD directory. If empty, the common name is used. (env: CONFIG_OPENVPN_CCD_TOKEN__CLAIM)
189200
--openvpn.common-name.environment-variable-name string
190201
Name of the environment variable in the OpenVPN management interface which contains the common name. If username-as-common-name is enabled, this should be set to 'username' to use the username as common name. Other values like 'X509_0_emailAddress' are supported. See https://openvpn.net/community-resources/reference-manual-for-openvpn-2-6/#environmental-variables for more information. (env: CONFIG_OPENVPN_COMMON__NAME_ENVIRONMENT__VARIABLE__NAME) (default "common_name")
191202
--openvpn.common-name.mode value
@@ -317,3 +328,7 @@ See [Layout Customization](Layout%20Customization) for more information
317328
## Non-interactive session refresh
318329
319330
See [Non-interactive session refresh](Non-interactive%20session%20refresh) for more information.
331+
332+
## Client specific configuration
333+
334+
See [Client specific configuration](Client%20specific%20configuration) for more information.

internal/config/defaults.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var Defaults = Config{
3232
},
3333
CallbackTemplate: template.Must(template.New("index.gohtml").ParseFS(ui.Template, "index.gohtml")),
3434
},
35-
OpenVpn: OpenVpn{
35+
OpenVpn: OpenVPN{
3636
Addr: &url.URL{
3737
Scheme: "unix",
3838
Path: "/run/openvpn/server.sock",
@@ -44,9 +44,13 @@ var Defaults = Config{
4444
EnvironmentVariableName: "common_name",
4545
Mode: CommonNameModePlain,
4646
},
47-
Bypass: OpenVpnBypass{
47+
Bypass: OpenVPNBypass{
4848
CommonNames: make([]string, 0),
4949
},
50+
CCD: OpenVPNCCD{
51+
Enabled: false,
52+
Path: "/etc/openvpn-auth-oauth2/ccd/",
53+
},
5054
Passthrough: OpenVPNPassthrough{
5155
Enabled: false,
5256
Address: &url.URL{

internal/config/flags.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const (
1616
func FlagSet(name string) *flag.FlagSet {
1717
flagSet := flag.NewFlagSet(name, flag.ContinueOnError)
1818
flagSet.Usage = func() {
19-
_, _ = fmt.Fprint(flagSet.Output(), "Documentation available at https://github.com/jkroepke/openvpn-auth-oauth2/wiki\r\n\r\n", name)
19+
_, _ = fmt.Fprint(flagSet.Output(), "Documentation available at https://github.com/jkroepke/openvpn-auth-oauth2/wiki\r\n\r\n")
2020
_, _ = fmt.Fprintf(flagSet.Output(), "Usage of %s:\r\n\r\n", name)
2121
// --help should display options with double dash
2222
flagSet.VisitAll(func(flag *flag.Flag) {
@@ -169,6 +169,21 @@ func flagSetOpenVPN(flagSet *flag.FlagSet) {
169169
Defaults.OpenVpn.Bypass.CommonNames,
170170
"bypass oauth authentication for CNs. Comma separated list.",
171171
)
172+
flagSet.Bool(
173+
"openvpn.ccd.enabled",
174+
Defaults.OpenVpn.CCD.Enabled,
175+
"If true, openvpn-auth-oauth2 will read the CCD directory for additional configuration. This function mimic the client-config-dir directive in OpenVPN.",
176+
)
177+
flagSet.String(
178+
"openvpn.ccd.path",
179+
Defaults.OpenVpn.CCD.Path,
180+
"Path to the CCD directory. openvpn-auth-oauth2 will look for an file with an .conf suffix and returns the content back.",
181+
)
182+
flagSet.String(
183+
"openvpn.ccd.token-claim",
184+
Defaults.OpenVpn.CCD.TokenClaim,
185+
"If non-empty, the value of the token claim is used to lookup the configuration file in the CCD directory. If empty, the common name is used.",
186+
)
172187
flagSet.String(
173188
"openvpn.common-name.environment-variable-name",
174189
Defaults.OpenVpn.CommonName.EnvironmentVariableName,

internal/config/flags_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func TestValidate(t *testing.T) {
171171
Client: config.OAuth2Client{ID: "ID", Secret: testutils.Secret},
172172
Issuer: &url.URL{Scheme: "http", Host: "localhost"},
173173
},
174-
OpenVpn: config.OpenVpn{
174+
OpenVpn: config.OpenVPN{
175175
Addr: &url.URL{Scheme: "tcp", Host: "127.0.0.1:9000"},
176176
},
177177
},
@@ -188,7 +188,7 @@ func TestValidate(t *testing.T) {
188188
Client: config.OAuth2Client{ID: "ID", Secret: testutils.Secret},
189189
Issuer: &url.URL{Scheme: "http", Host: "localhost"},
190190
},
191-
OpenVpn: config.OpenVpn{
191+
OpenVpn: config.OpenVPN{
192192
Addr: &url.URL{Scheme: "tcp", Host: "127.0.0.1:9000"},
193193
},
194194
},
@@ -205,7 +205,7 @@ func TestValidate(t *testing.T) {
205205
Client: config.OAuth2Client{ID: "ID", Secret: testutils.Secret},
206206
Issuer: &url.URL{Scheme: "http", Host: "localhost"},
207207
},
208-
OpenVpn: config.OpenVpn{
208+
OpenVpn: config.OpenVPN{
209209
Addr: &url.URL{Scheme: "quic", Host: "127.0.0.1:9000"},
210210
},
211211
},
@@ -225,7 +225,7 @@ func TestValidate(t *testing.T) {
225225
Enabled: true,
226226
},
227227
},
228-
OpenVpn: config.OpenVpn{
228+
OpenVpn: config.OpenVPN{
229229
Addr: &url.URL{Scheme: "tcp", Host: "127.0.0.1:9000"},
230230
},
231231
},
@@ -249,7 +249,7 @@ func TestValidate(t *testing.T) {
249249
Discovery: &url.URL{Scheme: "http", Host: "localhost"},
250250
},
251251
},
252-
OpenVpn: config.OpenVpn{
252+
OpenVpn: config.OpenVPN{
253253
Addr: &url.URL{Scheme: "tcp", Host: "127.0.0.1:9000"},
254254
},
255255
},

internal/config/load_test.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,13 @@ openvpn:
105105
common-names:
106106
- "test"
107107
- "test2"
108+
ccd:
109+
enabled: true
110+
token-claim: sub
111+
path: "."
108112
common-name:
109113
environment-variable-name: X509_0_emailAddress
110-
mode: omit
114+
mode: plain
111115
password: "1jd93h5b6s82lf03jh5b2hf9"
112116
pass-through:
113117
address: "unix:///run/openvpn/pass-through.sock"
@@ -146,21 +150,26 @@ http:
146150
},
147151
AssetPath: ".",
148152
},
149-
OpenVpn: config.OpenVpn{
153+
OpenVpn: config.OpenVPN{
150154
Addr: &url.URL{
151155
Scheme: "unix",
152156
Path: "/run/openvpn/server2.sock",
153157
OmitHost: false,
154158
},
155-
Bypass: config.OpenVpnBypass{
159+
Bypass: config.OpenVPNBypass{
156160
CommonNames: []string{"test", "test2"},
157161
},
162+
CCD: config.OpenVPNCCD{
163+
Enabled: true,
164+
TokenClaim: "sub",
165+
Path: ".",
166+
},
158167
Password: "1jd93h5b6s82lf03jh5b2hf9",
159168
AuthTokenUser: true,
160169
AuthPendingTimeout: 2 * time.Minute,
161170
CommonName: config.OpenVPNCommonName{
162171
EnvironmentVariableName: "X509_0_emailAddress",
163-
Mode: config.CommonNameModeOmit,
172+
Mode: config.CommonNameModePlain,
164173
},
165174
Passthrough: config.OpenVPNPassthrough{
166175
Enabled: true,

internal/config/types.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type Config struct {
1616
Debug Debug `koanf:"debug"`
1717
Log Log `koanf:"log"`
1818
HTTP HTTP `koanf:"http"`
19-
OpenVpn OpenVpn `koanf:"openvpn"`
19+
OpenVpn OpenVPN `koanf:"openvpn"`
2020
OAuth2 OAuth2 `koanf:"oauth2"`
2121
}
2222

@@ -43,20 +43,27 @@ type Log struct {
4343
VPNClientIP bool `koanf:"vpn-client-ip"`
4444
}
4545

46-
type OpenVpn struct {
46+
type OpenVPN struct {
4747
Addr *url.URL `koanf:"addr"`
4848
Password Secret `koanf:"password"`
49-
Bypass OpenVpnBypass `koanf:"bypass"`
49+
Bypass OpenVPNBypass `koanf:"bypass"`
50+
CCD OpenVPNCCD `koanf:"ccd"`
5051
AuthTokenUser bool `koanf:"auth-token-user"`
5152
AuthPendingTimeout time.Duration `koanf:"auth-pending-timeout"`
5253
CommonName OpenVPNCommonName `koanf:"common-name"`
5354
Passthrough OpenVPNPassthrough `koanf:"pass-through"`
5455
}
5556

56-
type OpenVpnBypass struct {
57+
type OpenVPNBypass struct {
5758
CommonNames StringSlice `koanf:"common-names"`
5859
}
5960

61+
type OpenVPNCCD struct {
62+
Enabled bool `koanf:"enabled"`
63+
TokenClaim string `koanf:"token-claim"`
64+
Path string `koanf:"path"`
65+
}
66+
6067
type OpenVPNCommonName struct {
6168
EnvironmentVariableName string `koanf:"environment-variable-name"`
6269
Mode OpenVPNCommonNameMode `koanf:"mode"`

internal/config/validate.go

+14
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,20 @@ func Validate(mode int, conf Config) error {
7777
if !slices.Contains([]string{"tcp", "unix"}, conf.OpenVpn.Addr.Scheme) {
7878
return errors.New("openvpn.addr: invalid URL. only tcp://addr or unix://addr scheme supported")
7979
}
80+
81+
if conf.OpenVpn.CCD.Enabled {
82+
if conf.OpenVpn.CCD.Path == "" {
83+
return fmt.Errorf("openvpn.ccd.path is %w, if openvpn.ccd.enabled=true", ErrRequired)
84+
}
85+
86+
if conf.OpenVpn.CommonName.Mode == CommonNameModeOmit {
87+
return errors.New("openvpn.common-name.mode: omit is not supported with openvpn.ccd.enabled")
88+
}
89+
90+
if _, err := os.ReadDir(conf.OpenVpn.CCD.Path); err != nil {
91+
return fmt.Errorf("openvpn.ccd.path: %w", err)
92+
}
93+
}
8094
}
8195

8296
if conf.HTTP.AssetPath != "" {

0 commit comments

Comments
 (0)