New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support running SPIRE as a Windows service #3625
Conversation
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
|
||
status := <-testCase.sc.statusCh | ||
assert.Equal(t, svc.Running, status.State) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @amartinezfayo, what do you think about making an interrogation here so we can cover this path asserting it returns the current state?
// Interrogate the service, which should return the current status. | |
testCase.sc.changeRequestCh <- svc.ChangeRequest{Cmd: svc.Interrogate} | |
status = <-testCase.sc.statusCh |
) | ||
|
||
func main() { | ||
os.Exit(new(cli.CLI).Run(os.Args[1:])) | ||
os.Exit(entrypoint.NewEntryPoint(new(cli.CLI).Run).Main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm worried that with this approach, any command will try to verify if our binary is running as a service,
but that is only true for "run" commands
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this and we agreed that in order to avoid blocking SPIRE to run only because the svc.IsWindowsService()
fails, we will fallback to run SPIRE as a regular process if IsWindowsService()
returns an error.
ctx := cmd.ctx | ||
if ctx == nil { | ||
ctx = context.Background() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may this initialization be moved to newRunCommand or NewRunCommand?
I know this is a double check... but sounds like if we require a context it must be set on struct initialization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if there is a real benefit of doing that. Currently, the context is being initialized here also, there is no change with that (https://github.com/spiffe/spire/blob/main/cmd/spire-server/cli/run/run.go#L244).
The cost of moving this to newRunCommand
would be that if the struct is being initialized without calling the newRunCommand
function (like we currently do in unit tests), we would need to set ctx
there. The intention of having it here is that a context is always provided if not specified.
What do you think?
@@ -166,6 +166,13 @@ the following flags are available: | |||
| `-trustBundleUrl` | URL to download the SPIRE server CA bundle | | | |||
| `-trustDomain` | The trust domain that this agent belongs to (should be no more than 255 characters) | | | |||
|
|||
#### Running SPIRE Agent as a Windows service | |||
|
|||
On Windows platform, SPIRE Agent can optionally be run as a Windows service. When running as a Windows service, the only command supported is the `run` command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how is this validation done? may we prevent it programmatically? what happens if a user try to create a service that run ./bin/spire-server bundle show
(it is unrealistic example)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a validation to fail with ERROR_BAD_ARGUMENTS if an argument indicating a command different to "run" is used when running as a service.
On Windows platform, SPIRE Agent can optionally be run as a Windows service. When running as a Windows service, the only command supported is the `run` command. | ||
|
||
_Note: SPIRE does not automatically create the service in the system, it must be created by the user. | ||
When starting the service, all the arguments to execute SPIRE Agent with the `run` command must be passed as service arguments._ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is something useful to provide an example here of a configuration that allows this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I'll add an example of how the service can be created and how the service can be run.
handler: &service{ | ||
RunFn: func(ctx context.Context, stop context.CancelFunc, args []string) int { | ||
retCode := runCmdFn(ctx, args[1:]) | ||
stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may we move stop to a defer?
changeRequestCh: make(chan svc.ChangeRequest, 1), | ||
statusCh: make(chan svc.Status, 1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: those channels can be created on test body, when isWindowsService == true
ep := newEntryPoint(func(ctx context.Context, args []string) int { | ||
return testCase.retCode | ||
}, testCase.sc) | ||
retCodeCh <- ep.Main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when main is closed? may we add a select with this + ctx.Done()?
// This is running as a service. | ||
// Check if we expect a failure running the service. | ||
if testCase.retCode != 0 { | ||
assert.Equal(t, testCase.retCode, <-retCodeCh) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about adding a select here too? so we can be sure we return something before our ctx is finished (ctx with timeout)
// Final status should be Stopped. | ||
assert.Equal(t, svc.Stopped, (<-testCase.sc.statusCh).State) | ||
|
||
assert.Equal(t, false, testCase.sc.svcSpecificEC) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert.IsFalse
} | ||
|
||
status <- svc.Status{State: svc.StopPending} | ||
stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defer after creation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be here to prevent races with the retCode.
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great a couple comments on docs to pass lints
doc/spire_agent.md
Outdated
@@ -173,6 +173,18 @@ On Windows platform, SPIRE Agent can optionally be run as a Windows service. Whe | |||
_Note: SPIRE does not automatically create the service in the system, it must be created by the user. | |||
When starting the service, all the arguments to execute SPIRE Agent with the `run` command must be passed as service arguments._ | |||
|
|||
##### Example to create the SPIRE Agent Windows service | |||
|
|||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you will need to add type here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type is already added, I think that this was commented from a previous commit.
doc/spire_agent.md
Outdated
##### Example to create the SPIRE Agent Windows service | ||
|
||
``` | ||
sc.exe create spire-agent binpath=c:\spire\bin\spire-agent.exe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since it is a shell may we add $
at the start?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
>
probably fits better for a Windows terminal / command prompt?
Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!!!
* Support running SPIRE as a Windows service Signed-off-by: Agustín Martínez Fayó <amartinezfayo@gmail.com>
Add support in SPIRE to run both SPIRE Server and SPIRE Agent as a Windows service.
Fixes #3490.