Skip to content

Commit

Permalink
Merge pull request #13645 from tomponline/stable-5.21
Browse files Browse the repository at this point in the history
Backports (stable-5.21)
  • Loading branch information
tomponline authored Jun 21, 2024
2 parents 6436354 + 206bda6 commit e5101ce
Show file tree
Hide file tree
Showing 107 changed files with 8,855 additions and 8,146 deletions.
18 changes: 11 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,14 @@ jobs:
CGO_ENABLED=0 go build -trimpath -o "/tmp/bin/lxd-agent" -tags=agent,netgo github.com/canonical/lxd/lxd-agent
strip -s /tmp/bin/*
# bin/min/max (sizes are in MiB)
SIZES="lxc 13 14
lxd-agent 11 12"
# bin/max (sizes are in MiB)
SIZES="lxc 15
lxd-agent 12"
MIB="$((1024 * 1024))"
while read -r bin min max; do
while read -r bin max; do
cur="$(stat --format=%s "/tmp/bin/${bin}")"
min=$((max - 1))
min_mib="$((min * MIB))"
max_mib="$((max * MIB))"
rm -f "/tmp/bin/${bin}"
Expand Down Expand Up @@ -241,11 +242,14 @@ jobs:
with:
go-version: ${{ matrix.go }}

- name: Check compatibility with min Go version (${{ matrix.go }})
if: matrix.go == '1.22.x'
- name: Check compatibility with min Go version
run: |
set -eux
go mod tidy -go=1.22.3
GOMIN="$(sed -n 's/^GOMIN=\([0-9.]\+\)$/\1/p' Makefile)"
go mod tidy -go="${GOMIN}"
DOC_GOMIN="$(sed -n 's/^LXD requires Go \([0-9.]\+\) .*/\1/p' doc/requirements.md)"
[ "${GOMIN}" = "${DOC_GOMIN}" ]
- name: Install dependencies
run: |
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GOPATH ?= $(shell go env GOPATH)
CGO_LDFLAGS_ALLOW ?= (-Wl,-wrap,pthread_create)|(-Wl,-z,now)
SPHINXENV=doc/.sphinx/venv/bin/activate
SPHINXPIPPATH=doc/.sphinx/venv/bin/pip
GOMIN=1.22.3
GOMIN=1.22.4

ifneq "$(wildcard vendor)" ""
DQLITE_PATH=$(CURDIR)/vendor/dqlite
Expand Down
20 changes: 12 additions & 8 deletions client/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"time"

"github.com/gorilla/websocket"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/oidc"

"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
Expand Down Expand Up @@ -155,8 +155,9 @@ func ConnectLXDUnix(path string, args *ConnectionArgs) (InstanceServer, error) {
// ConnectLXDUnixWithContext lets you connect to a remote LXD daemon over a local unix socket with context.Context.
//
// If the path argument is empty, then $LXD_SOCKET will be used, if
// unset $LXD_DIR/unix.socket will be used and if that one isn't set
// either, then the path will default to /var/lib/lxd/unix.socket.
// unset $LXD_DIR/unix.socket will be used, if that one isn't set
// either, then the path will default to /var/snap/lxd/common/lxd/unix.socket
// if the file exists and is writable or /var/lib/lxd/unix.socket otherwise.
func ConnectLXDUnixWithContext(ctx context.Context, path string, args *ConnectionArgs) (InstanceServer, error) {
logger.Debug("Connecting to a local LXD over a Unix socket")

Expand Down Expand Up @@ -185,16 +186,19 @@ func ConnectLXDUnixWithContext(ctx context.Context, path string, args *Connectio
eventListeners: make(map[string][]*EventListener),
}

// Determine the socket path
// Determine the socket path.
if path == "" {
path = os.Getenv("LXD_SOCKET")
if path == "" {
lxdDir := os.Getenv("LXD_DIR")
if lxdDir == "" {
lxdDir = "/var/lib/lxd"
if lxdDir != "" {
path = filepath.Join(lxdDir, "unix.socket")
} else {
path = "/var/snap/lxd/common/lxd/unix.socket"
if !shared.PathIsWritable(path) {
path = "/var/lib/lxd/unix.socket"
}
}

path = filepath.Join(lxdDir, "unix.socket")
}
}

Expand Down
11 changes: 9 additions & 2 deletions client/lxd_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/canonical/lxd/shared/api"
)

// GetCluster returns information about a cluster
// GetCluster returns information about a cluster.
//
// If this client is not trusted, the password must be supplied.
func (r *ProtocolLXD) GetCluster() (*api.Cluster, string, error) {
Expand All @@ -31,11 +31,18 @@ func (r *ProtocolLXD) UpdateCluster(cluster api.ClusterPut, ETag string) (Operat
return nil, err
}

if cluster.ServerAddress != "" || cluster.ClusterPassword != "" || len(cluster.MemberConfig) > 0 {
if cluster.ServerAddress != "" || cluster.ClusterPassword != "" || cluster.ClusterToken != "" || len(cluster.MemberConfig) > 0 {
err := r.CheckExtension("clustering_join")
if err != nil {
return nil, err
}

if cluster.ClusterToken != "" {
err := r.CheckExtension("explicit_trust_token")
if err != nil {
return nil, err
}
}
}

op, _, err := r.queryOperation("PUT", "/cluster", cluster, "", true)
Expand Down
18 changes: 11 additions & 7 deletions client/lxd_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ func (r *ProtocolLXD) GetImageSecret(fingerprint string) (string, error) {

opAPI := op.Get()

return opAPI.Metadata["secret"].(string), nil
secret, ok := opAPI.Metadata["secret"].(string)
if !ok {
return "", fmt.Errorf("Failed to extract image secret from operation metadata")
}

return secret, nil
}

// GetPrivateImage is similar to GetImage but allows passing a secret download token.
Expand Down Expand Up @@ -409,7 +414,6 @@ func (r *ProtocolLXD) CreateImage(image api.ImagesPost, args *ImageCreateArgs) (
}

// Prepare the body
var ioErr error
var body io.Reader
var contentType string
if args.RootfsFile == nil {
Expand Down Expand Up @@ -547,10 +551,6 @@ func (r *ProtocolLXD) CreateImage(image api.ImagesPost, args *ImageCreateArgs) (

defer func() { _ = resp.Body.Close() }()

if ioErr != nil {
return nil, err
}

// Handle errors
response, _, err := lxdParseResponse(resp)
if err != nil {
Expand Down Expand Up @@ -607,7 +607,11 @@ func (r *ProtocolLXD) tryCopyImage(req api.ImagesPost, urls []string) (RemoteOpe
}

// Extract the fingerprint
fingerprint := op.Metadata["fingerprint"].(string)
fingerprint, ok := op.Metadata["fingerprint"].(string)
if !ok {
rop.err = remoteOperationError("Failed to extract fingerprint from operation metadata", errors)
return
}

// Add the aliases
for _, entry := range req.Aliases {
Expand Down
24 changes: 15 additions & 9 deletions client/lxd_oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
"syscall"
"time"

"github.com/zitadel/oidc/v2/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v2/pkg/http"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/client/rp"
httphelper "github.com/zitadel/oidc/v3/pkg/http"
"github.com/zitadel/oidc/v3/pkg/oidc"
"golang.org/x/oauth2"
)

Expand Down Expand Up @@ -164,7 +164,10 @@ func (o *oidcClient) getProvider(issuer string, clientID string, groupsClaim str
scopes = append(oidcScopes, groupsClaim)
}

provider, err := rp.NewRelyingPartyOIDC(issuer, clientID, "", "", scopes, options...)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

provider, err := rp.NewRelyingPartyOIDC(ctx, issuer, clientID, "", "", scopes, options...)
if err != nil {
return nil, err
}
Expand All @@ -184,7 +187,10 @@ func (o *oidcClient) refresh(issuer string, clientID string, groupsClaim string)
return errRefreshAccessToken
}

oauthTokens, err := rp.RefreshAccessToken(provider, o.tokens.RefreshToken, "", "")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

oauthTokens, err := rp.RefreshTokens[*oidc.IDTokenClaims](ctx, provider, o.tokens.RefreshToken, "", "")
if err != nil {
return errRefreshAccessToken
}
Expand Down Expand Up @@ -220,7 +226,10 @@ func (o *oidcClient) authenticate(issuer string, clientID string, audience strin

o.oidcTransport.deviceAuthorizationEndpoint = provider.GetDeviceAuthorizationEndpoint()

resp, err := rp.DeviceAuthorization(oidcScopes, provider)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT)
defer stop()

resp, err := rp.DeviceAuthorization(ctx, oidcScopes, provider, nil)
if err != nil {
return err
}
Expand All @@ -232,9 +241,6 @@ func (o *oidcClient) authenticate(issuer string, clientID string, audience strin

_ = openBrowser(u.String())

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT)
defer stop()

token, err := rp.DeviceAccessToken(ctx, resp.DeviceCode, time.Duration(resp.Interval)*time.Second, provider)
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions doc/.readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ version: 2
build:
os: ubuntu-22.04
tools:
golang: "1.21"
python: "3.11"
golang: "1.22"
python: "3.12"
jobs:
pre_install:
- pip install gitpython pyyaml
Expand Down
5 changes: 5 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2419,3 +2419,8 @@ Adds the ability to use an unspecified IPv4 (`0.0.0.0`) or IPv6 (`::`) address i
If an unspecified IP address is used, supported drivers will allocate an available listen address automatically.
Allocation of external IP addresses is currently supported by the OVN network driver.
The OVN driver will allocate IP addresses from the subnets specified in the uplink network's `ipv4.routes` and `ipv6.routes` configuration options.

## `explicit_trust_token`

Adds the ability to explicitly specify a trust token when creating a certificate
and joining an existing cluster.
2 changes: 1 addition & 1 deletion doc/config_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2026,7 +2026,7 @@ See {ref}`instance-options-limits-hugepages` for more information.
```

```{config:option} limits.memory instance-resource-limits
:defaultdesc: "`1Gib` (VMs)"
:defaultdesc: "`1GiB` (VMs)"
:liveupdate: "yes"
:shortdesc: "Usage limit for the host's memory"
:type: "string"
Expand Down
74 changes: 65 additions & 9 deletions doc/howto/projects_confine.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,18 @@ See {ref}`authentication-tls-certs` for detailed information.
To confine the access from the time the client certificate is added, you must either use token authentication or add the client certificate to the server directly.
If you use password authentication, you can restrict the client certificate only after it has been added.

Use the following command to add a restricted client certificate:
Follow these instructions:

````{tabs}
`````{tabs}
````{group-tab} CLI
```{group-tab} Token authentication
If you're using token authentication:
lxc config trust add --projects <project_name> --restricted
```
```{group-tab} Add client certificate
To add the client certificate directly:
lxc config trust add <certificate_file> --projects <project_name> --restricted
```
````
The client can then add the server as a remote in the usual way ([`lxc remote add <server_name> <token>`](lxc_remote_add.md) or [`lxc remote add <server_name> <server_address>`](lxc_remote_add.md)) and can only access the project or projects that have been specified.
Expand All @@ -48,6 +44,66 @@ This configuration pre-selects the specified project.
However, it does not confine the client to this project.
```
````
````{group-tab} API
If you're using token authentication, create the token first:
lxc query --request POST /1.0/certificates --data '{
"name": "<client_name>",
"projects": ["<project_name>"]
"restricted": true,
"token": true,
"type": "client",
}'
% Include content from [/howto/server_expose.md](/howto/server_expose.md)
```{include} /howto/server_expose.md
:start-after: <!-- include start token API -->
:end-before: <!-- include end token API -->
```
To instead add the client certificate directly, send the following request:
lxc query --request POST /1.0/certificates --data '{
"certificate": "<certificate>",
"name": "<client_name>",
"projects": ["<project_name>"]
"restricted": true,
"token": false,
"type": "client",
}'
The client can then authenticate using this trust token or client certificate and can only access the project or projects that have been specified.
% Include content from [/howto/server_expose.md](/howto/server_expose.md)
```{include} /howto/server_expose.md
:start-after: <!-- include start authenticate API -->
:end-before: <!-- include end authenticate API -->
```
````
`````

To confine access for an existing certificate:

````{tabs}
```{group-tab} CLI
Use the following command:
lxc config trust edit <fingerprint>
```
```{group-tab} API
Send the following request:
lxc query --request PATCH /1.0/certificates/<fingerprint> --data '{
"projects": ["<project_name>"],
"restricted": true
}'
```
````

Make sure that `restricted` is set to `true` and specify the projects that the certificate should give access to under `projects`.

(projects-confine-users)=
## Confine projects to specific LXD users

Expand Down
Loading

0 comments on commit e5101ce

Please sign in to comment.