mirror of
https://github.com/fatedier/frp.git
synced 2026-07-21 05:49:18 +08:00
Compare commits
6 Commits
7285b44b04
...
v0.66.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1348cdf00 | ||
|
|
33428ab538 | ||
|
|
ef96481f58 | ||
|
|
2f5e1f7945 | ||
|
|
22ae8166d3 | ||
|
|
af6bc6369d |
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
* HTTPS proxies now support load balancing groups. Multiple HTTPS proxies can be configured with the same `loadBalancer.group` and `loadBalancer.groupKey` to share the same custom domain and distribute traffic across multiple backend services, similar to the existing TCP and HTTP load balancing capabilities.
|
* HTTPS proxies now support load balancing groups. Multiple HTTPS proxies can be configured with the same `loadBalancer.group` and `loadBalancer.groupKey` to share the same custom domain and distribute traffic across multiple backend services, similar to the existing TCP and HTTP load balancing capabilities.
|
||||||
* Individual frpc proxies and visitors now accept an `enabled` flag (defaults to true), letting you disable specific entries without relying on the global `start` list—disabled blocks are skipped when client configs load.
|
* Individual frpc proxies and visitors now accept an `enabled` flag (defaults to true), letting you disable specific entries without relying on the global `start` list—disabled blocks are skipped when client configs load.
|
||||||
|
* OIDC authentication now supports a `tokenSource` field to dynamically obtain tokens from external sources. You can use `type = "file"` to read a token from a file, or `type = "exec"` to run an external command (e.g., a cloud CLI or secrets manager) and capture its stdout as the token. The `exec` type requires the `--allow-unsafe=TokenSourceExec` CLI flag for security reasons.
|
||||||
|
|
||||||
## Improvements
|
## Improvements
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
var version = "0.65.0"
|
var version = "0.66.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
|||||||
@@ -29,6 +29,18 @@ import (
|
|||||||
var _ = ginkgo.Describe("[Feature: TokenSource]", func() {
|
var _ = ginkgo.Describe("[Feature: TokenSource]", func() {
|
||||||
f := framework.NewDefaultFramework()
|
f := framework.NewDefaultFramework()
|
||||||
|
|
||||||
|
createExecTokenScript := func(name string) string {
|
||||||
|
scriptPath := filepath.Join(f.TempDirectory, name)
|
||||||
|
scriptContent := `#!/bin/sh
|
||||||
|
printf '%s\n' "$1"
|
||||||
|
`
|
||||||
|
err := os.WriteFile(scriptPath, []byte(scriptContent), 0o600)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
err = os.Chmod(scriptPath, 0o700)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
return scriptPath
|
||||||
|
}
|
||||||
|
|
||||||
ginkgo.Describe("File-based token loading", func() {
|
ginkgo.Describe("File-based token loading", func() {
|
||||||
ginkgo.It("should work with file tokenSource", func() {
|
ginkgo.It("should work with file tokenSource", func() {
|
||||||
// Create a temporary token file
|
// Create a temporary token file
|
||||||
@@ -214,4 +226,154 @@ auth.tokenSource.file.path = "%s"
|
|||||||
f.RunProcesses([]string{serverConf}, []string{})
|
f.RunProcesses([]string{serverConf}, []string{})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ginkgo.Describe("Exec-based token loading", func() {
|
||||||
|
ginkgo.It("should work with server tokenSource", func() {
|
||||||
|
execValue := "exec-server-value"
|
||||||
|
scriptPath := createExecTokenScript("server_token_exec.sh")
|
||||||
|
|
||||||
|
serverPort := f.AllocPort()
|
||||||
|
remotePort := f.AllocPort()
|
||||||
|
|
||||||
|
serverConf := fmt.Sprintf(`
|
||||||
|
bindAddr = "0.0.0.0"
|
||||||
|
bindPort = %d
|
||||||
|
|
||||||
|
auth.tokenSource.type = "exec"
|
||||||
|
auth.tokenSource.exec.command = %q
|
||||||
|
auth.tokenSource.exec.args = [%q]
|
||||||
|
`, serverPort, scriptPath, execValue)
|
||||||
|
|
||||||
|
clientConf := fmt.Sprintf(`
|
||||||
|
serverAddr = "127.0.0.1"
|
||||||
|
serverPort = %d
|
||||||
|
loginFailExit = false
|
||||||
|
auth.token = %q
|
||||||
|
|
||||||
|
[[proxies]]
|
||||||
|
name = "tcp"
|
||||||
|
type = "tcp"
|
||||||
|
localPort = %d
|
||||||
|
remotePort = %d
|
||||||
|
`, serverPort, execValue, f.PortByName(framework.TCPEchoServerPort), remotePort)
|
||||||
|
|
||||||
|
serverConfigPath := f.GenerateConfigFile(serverConf)
|
||||||
|
clientConfigPath := f.GenerateConfigFile(clientConf)
|
||||||
|
|
||||||
|
_, _, err := f.RunFrps("-c", serverConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
_, _, err = f.RunFrpc("-c", clientConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).Port(remotePort).Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should work with client tokenSource", func() {
|
||||||
|
execValue := "exec-client-value"
|
||||||
|
scriptPath := createExecTokenScript("client_token_exec.sh")
|
||||||
|
|
||||||
|
serverPort := f.AllocPort()
|
||||||
|
remotePort := f.AllocPort()
|
||||||
|
|
||||||
|
serverConf := fmt.Sprintf(`
|
||||||
|
bindAddr = "0.0.0.0"
|
||||||
|
bindPort = %d
|
||||||
|
|
||||||
|
auth.token = %q
|
||||||
|
`, serverPort, execValue)
|
||||||
|
|
||||||
|
clientConf := fmt.Sprintf(`
|
||||||
|
serverAddr = "127.0.0.1"
|
||||||
|
serverPort = %d
|
||||||
|
loginFailExit = false
|
||||||
|
|
||||||
|
auth.tokenSource.type = "exec"
|
||||||
|
auth.tokenSource.exec.command = %q
|
||||||
|
auth.tokenSource.exec.args = [%q]
|
||||||
|
|
||||||
|
[[proxies]]
|
||||||
|
name = "tcp"
|
||||||
|
type = "tcp"
|
||||||
|
localPort = %d
|
||||||
|
remotePort = %d
|
||||||
|
`, serverPort, scriptPath, execValue, f.PortByName(framework.TCPEchoServerPort), remotePort)
|
||||||
|
|
||||||
|
serverConfigPath := f.GenerateConfigFile(serverConf)
|
||||||
|
clientConfigPath := f.GenerateConfigFile(clientConf)
|
||||||
|
|
||||||
|
_, _, err := f.RunFrps("-c", serverConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
_, _, err = f.RunFrpc("-c", clientConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).Port(remotePort).Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should work with both server and client tokenSource", func() {
|
||||||
|
execValue := "exec-shared-value"
|
||||||
|
scriptPath := createExecTokenScript("shared_token_exec.sh")
|
||||||
|
|
||||||
|
serverPort := f.AllocPort()
|
||||||
|
remotePort := f.AllocPort()
|
||||||
|
|
||||||
|
serverConf := fmt.Sprintf(`
|
||||||
|
bindAddr = "0.0.0.0"
|
||||||
|
bindPort = %d
|
||||||
|
|
||||||
|
auth.tokenSource.type = "exec"
|
||||||
|
auth.tokenSource.exec.command = %q
|
||||||
|
auth.tokenSource.exec.args = [%q]
|
||||||
|
`, serverPort, scriptPath, execValue)
|
||||||
|
|
||||||
|
clientConf := fmt.Sprintf(`
|
||||||
|
serverAddr = "127.0.0.1"
|
||||||
|
serverPort = %d
|
||||||
|
loginFailExit = false
|
||||||
|
|
||||||
|
auth.tokenSource.type = "exec"
|
||||||
|
auth.tokenSource.exec.command = %q
|
||||||
|
auth.tokenSource.exec.args = [%q]
|
||||||
|
|
||||||
|
[[proxies]]
|
||||||
|
name = "tcp"
|
||||||
|
type = "tcp"
|
||||||
|
localPort = %d
|
||||||
|
remotePort = %d
|
||||||
|
`, serverPort, scriptPath, execValue, f.PortByName(framework.TCPEchoServerPort), remotePort)
|
||||||
|
|
||||||
|
serverConfigPath := f.GenerateConfigFile(serverConf)
|
||||||
|
clientConfigPath := f.GenerateConfigFile(clientConf)
|
||||||
|
|
||||||
|
_, _, err := f.RunFrps("-c", serverConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
_, _, err = f.RunFrpc("-c", clientConfigPath, "--allow-unsafe=TokenSourceExec")
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
framework.NewRequestExpect(f).Port(remotePort).Ensure()
|
||||||
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should fail validation without allow-unsafe", func() {
|
||||||
|
execValue := "exec-unsafe-value"
|
||||||
|
scriptPath := createExecTokenScript("unsafe_token_exec.sh")
|
||||||
|
|
||||||
|
serverPort := f.AllocPort()
|
||||||
|
serverConf := fmt.Sprintf(`
|
||||||
|
bindAddr = "0.0.0.0"
|
||||||
|
bindPort = %d
|
||||||
|
|
||||||
|
auth.tokenSource.type = "exec"
|
||||||
|
auth.tokenSource.exec.command = %q
|
||||||
|
auth.tokenSource.exec.args = [%q]
|
||||||
|
`, serverPort, scriptPath, execValue)
|
||||||
|
|
||||||
|
serverConfigPath := f.GenerateConfigFile(serverConf)
|
||||||
|
|
||||||
|
_, output, err := f.RunFrps("verify", "-c", serverConfigPath)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
framework.ExpectContainSubstring(output, "unsafe feature \"TokenSourceExec\" is not enabled")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user