Migrate from simplified to multi-user S3
Your team has grown past the point where one shared IAM user makes sense. This guide upgrades you to per-user credentials with RBAC, without re-uploading a single byte.
Estimated time: 20–30 min · Last reviewed: 2026-05 · Difficulty: Intermediate
Before you start
- You currently have a working Cloud Gallery on Amazon S3 using the simplified single-user setup
- You can sign in to the AWS Management Console as root or as an IAM user with full IAM and S3 permissions
- You're a team admin (super-admin) inside webQsee, only admins can change team-wide Cloud settings
- Active webQsee Professional or Team plan, see pricing
The good news
Nothing in the bucket needs to move. The objects already live under /shared/, /protected/ and /private/, which are the exact prefixes the multi-user policies expect. The only thing that changes is who can do what, not where data is stored. No data migration, no downtime for already-uploaded items.
Migration plan
Six phases:
- Add the
webqsee-userpolicy you didn't create the first time. - Add the
webqsee-usergroup. - Create one IAM user per real team member, each with the
webqsee-user-idtag. - Distribute the new credentials.
- Flip the team-wide setting in webQsee from "single shared" to "per-user credentials".
- Retire (or keep) the old shared IAM user.
1. Add the webqsee-user IAM policy
This is the per-user policy that uses the aws:PrincipalTag/webqsee-user-id condition to give each IAM user write access only to their own /private/<user-id>/ prefix.
Open IAM → Policies → Create policy
Sign in to AWS, navigate to IAM → Policies → Create policy → JSON.
Sanity check: The empty JSON editor is open.Paste the user policy JSON
If your bucket is named something other than
webqsee, replace it in the ARNs below.{ "Version": "2012-10-17", "Statement": [ { "Sid": "UserListBucketScoped", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetBucketLocation", "s3:GetBucketCors" ], "Resource": "arn:aws:s3:::webqsee", "Condition": { "StringLike": { "s3:prefix": [ "shared/*", "shared/", "protected/*", "protected/", "private/${aws:PrincipalTag/webqsee-user-id}/*", "private/${aws:PrincipalTag/webqsee-user-id}/", "" ] } } }, { "Sid": "UserSharedReadWrite", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectTagging", "s3:PutObject", "s3:PutObjectTagging", "s3:DeleteObject", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts" ], "Resource": "arn:aws:s3:::webqsee/shared/*" }, { "Sid": "UserPrivateReadWrite", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectTagging", "s3:PutObject", "s3:PutObjectTagging", "s3:DeleteObject", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts" ], "Resource": "arn:aws:s3:::webqsee/private/${aws:PrincipalTag/webqsee-user-id}/*" }, { "Sid": "UserProtectedReadOnly", "Effect": "Allow", "Action": ["s3:GetObject", "s3:GetObjectTagging"], "Resource": "arn:aws:s3:::webqsee/protected/*" } ] }Sanity check: JSON validates without errors. Click Next and confirm the review screen lists four statements.Save as
webqsee-userName:
webqsee-user. Description: "webQsee Cloud Gallery, per-user, tag-scoped /private". Click Create policy.Sanity check: The Customer managed policies list now contains bothwebqsee-admin(from the original setup) and the newwebqsee-user.
2. Create the webqsee-user group
Create the group
IAM → User groups → Create group. Name:
webqsee-user. Attach thewebqsee-userpolicy. Click Create group.Sanity check: Two groups now exist:webqsee-admin(from before) andwebqsee-user(new), each with 1 attached policy.
3. Create one IAM user per team member
Collect webQsee user IDs
Open webQsee → Settings → Current User and Team. The team roster shows the User ID for every member. Write them down (name → ID).
Sanity check: You have a complete (name, webQsee user ID) mapping for every member who needs cloud access.Create one IAM user per member
IAM → Users → Create user. For each:
- Username:
<first-name>-webqsee(e.g.alice-webqsee) - Do not grant console access
- Group:
webqsee-user(orwebqsee-adminfor power users who should be able to write to/protected/) - Tag: key
webqsee-user-id, value = that person's webQsee user ID (exact case)
Sanity check: IAM → Users shows one IAM user per real team member, each Active, each in the right group, each with the matchingwebqsee-user-idtag visible on their Tags tab.- Username:
Generate access keys
For every new user: Security credentials → Create access key → Application running outside AWS. Save the Access Key ID + Secret immediately, secrets are shown once.
Sanity check: You have one (Access Key ID, Secret) pair stored per team member in your password manager.
4. Distribute credentials securely
Send each member their own pair
Use an encrypted channel: 1Password sharing, Bitwarden Send, signed PGP email, Keybase, etc. Never paste secrets in Slack/Teams/Email in clear text. Each member only needs their own Access Key ID and Secret, the team-wide bucket name and region come down automatically from webQsee.
Sanity check: Each member confirms receipt of their own credentials before you continue.
5. Flip webQsee from single-shared to multi-user mode
Open team-wide Cloud settings
webQsee → main window → Gallery → Cloud Gallery → Edit Settings → Team-wide section.
Sanity check: You see the current settings: Storage Type = "S3 compatible storage, KEY-Auth", Authentication mode = "Single shared credentials".Switch the authentication mode
Change Authentication mode from
Single shared credentials (simplified)toPer-user credentials (multi-user). Bucket name, region and CORS stay the same.The shared Access Key / Secret fields will be replaced by a personal credentials section.
Sanity check: A confirmation dialog warns "Switching to multi-user will require every team member to enter their own credentials". Click Confirm.Save the team-wide change
Click Save team settings. The shared key is no longer used.
Sanity check: Toast "Team cloud settings updated". The panel header reads "Cloud storage requires personal credentials".Enter your own personal credentials
In the Personal section paste your Access Key ID and Secret (the ones generated for your IAM user in step 3). Click Save personal credentials.
Sanity check: "Cloud Storage connected ✓" lights up green. Open the Cloud Gallery's Shared tab, the items you uploaded under the old shared user are still there.Ask team members to do the same
Each member opens their own webQsee, sees a prompt "Team has switched to per-user credentials, please enter your Access Key", and pastes their own pair.
Sanity check: Every team member reports "Cloud Storage connected ✓" and can see existing Shared and Protected items unchanged.Verify per-user isolation
Have one user upload a screenshot to Private. Confirm it appears under
private/<their-webqsee-id>/in the S3 console. Have a second user try (via webQsee) to view it, they shouldn't see it in their own Private tab.Sanity check: S3 console shows the new object underprivate/u_8f3c9a1e/…(the uploader's ID). The other user's Private tab does not show it.
6. (Optional) Retire the old shared IAM user
Confirm nothing depends on it anymore
Wait a day. Confirm with the team that uploads, downloads and deletes all work with the new per-user setup. Keep a screenshot or note of which user holds which Access Key ID, in case you need a forensic trail.
Sanity check: No team member reports CORS, 403 or "connection lost" errors. Everyone is on per-user credentials.Deactivate the old shared user's access key
IAM → Users →
webqsee-shared→ Security credentials. Find the existing access key and click Make inactive. Wait 24 hours; if nothing breaks, click Delete.Sanity check: The access key shows Status: Inactive. webQsee Cloud Gallery still works for everyone because they now use their own keys.(Optional) Delete the IAM user itself
Once the access key is gone for 24h with no issues, IAM → Users →
webqsee-shared→ Delete.Sanity check:webqsee-sharedno longer appears in the Users list. Only the per-person IAM users remain.
Final sanity check
Open webQsee → Gallery → Cloud Gallery on at least two different members' machines. Both should see "Cloud Storage connected ✓". Each should see the same Shared items. Each should see only their own Private items.
In the AWS S3 console, the bucket layout should be unchanged structurally, shared/, protected/, private/<id>/…, just now with per-user authorisation.
Troubleshooting
- "Cannot save team settings, mode not allowed": the bucket has objects under
/private/that don't match any current member's webQsee ID. Either delete those stragglers in the S3 console or temporarily widen the policy. (This usually only happens if you had ad-hoc paths from prior experiments.) - 403 on existing items after switching: a member can no longer download something they previously uploaded under the simplified scheme. Cause: the object lives under
/private/but at a path that doesn't match theirwebqsee-user-id. Move the object to the correct user's prefix using the S3 console (Copy → Move) or to/shared/. - "Access denied to /private/" for the uploader of a brand-new object: the IAM user is missing the
webqsee-user-idtag or its value differs from the webQsee user ID. Re-check step 3 step 2. - One user still works with the old shared key: webQsee caches credentials. Ask them to Edit Settings → Personal → Clear → Save and then re-paste their own pair.
- CORS error after the switch: should not happen, CORS is bucket-level and doesn't change. Re-apply the CORS JSON from the multi-user tutorial step 7 if needed.
Related tutorials
Multi-user S3 with RBAC
The full reference for the multi-user setup you're migrating to.
Open tutorialSimplified S3 integration
The original setup you're moving away from, useful as a reference.
Open tutorialStop guessing. Start webQseeing.
Add webQsee to Chrome or Edge in one click. Most features are free, forever, no signup needed. Upgrade only if your team needs cloud sharing, S3 storage and Pro-grade tooling.
Works in Chrome 103+, Edge 103+ and most Chromium-based browsers. Install instructions.