How do you bootstrap your CI runner permissions?

I thought I’d throw this discussion out to a wider audience while I have it floating around in my head.

At $DAYJOB, when configuring up a new environment (one “env” per subscription), the CI runner (Self Hosted GitHub Actions runner) doesn’t have any permissions to do anything. In order to bootstrap the process I manually (with a shell script so that it is repeatable) create a storage account for state and I’ve documented all of the role assignments (mostly built in roles) I’ve performed to give the runner access to only the resources it needs to manage. While this works it is a little clunky.

I’m currently bootstrapping a hobby project on GitLab. I’m using the GitLab http state store, so that solves one problem really nicely. As this is a hobby project I don’t want to spin up any self hosted runners, so I manually created an App Registration for the CI process to use. The next step is assigning permissions to the CI “App” and I’m wondering if anyone has found a cleverer way than what I did before.

I’m currently considering checking a custom role definition json into the repo, so that bootstrapping would be a single role to be updated manually through the CLI, although I fear a single role could quickly get messy not being very clear which resources need which roles.

Any advice?