asf-tooling commented on issue #437:
URL: 
https://github.com/apache/tooling-trusted-releases/issues/437#issuecomment-4410319158

   <!-- gofannon-issue-triage-bot v2 -->
   
   **Automated triage** — analyzed at `main@2da7807a`
   
   **Type:** `discussion`  •  **Classification:** `no_action`  •  
**Confidence:** `high`
   **Application domain(s):** `cryptographic_keys`, `automated_checks`, 
`authentication_authorization`
   
   ### Summary
   This is an open-ended RFC exploring alternatives to local OpenPGP signing 
for ASF releases. The issue discusses Sigstore adoption (as Python SF did), 
server-side signing with password-protected private keys on ATR, and WebAuthn 
requirements. @sbp noted in a follow-up that the tooling-releases-client (issue 
#3) could add a signing command to ease the process client-side. No concrete 
implementation decision has been made, and no specific code change is proposed 
— this remains a design discussion about the overall signing architecture.
   
   ### Where this lives in the code today
   
   #### `atr/tasks/checks/signature.py` — `check` (lines 38-50)
   _currently does this_
   The existing signature check is tightly coupled to OpenPGP .asc detached 
signatures; any alternative signing scheme would need a parallel check or this 
would need abstraction.
   
   ```python
   async def check(args: checks.FunctionArguments) -> results.Results | None:
       """Check a signature file."""
       recorder = await args.recorder(CHECK_VERSION)
       if not (primary_abs_path := await recorder.abs_path()):
           return None
   
       if not (primary_rel_path := args.primary_rel_path):
           await recorder.exception("Primary relative path is required", 
{"primary_rel_path": primary_rel_path})
           return None
   
       artifact_rel_path = str(primary_rel_path).removesuffix(".asc")
       if not (artifact_abs_path := await recorder.abs_path(artifact_rel_path)):
           return None
   ```
   
   #### `atr/tasks/checks/signature.py` — `_check_core_logic` (lines 82-93)
   _currently does this_
   Core verification logic fetches OpenPGP public keys from the database. A 
server-side signing approach would store private keys here too, requiring new 
DB models and storage.
   
   ```python
   async def _check_core_logic(committee_key: str, artifact_path: str, 
signature_path: str) -> dict[str, Any]:
       """Verify a signature file using the committee's public signing keys."""
       log.info(f"Attempting to fetch keys for committee_key: 
'{committee_key}'")
       async with db.session() as session:
           statement = (
               sqlmodel.select(sql.PublicSigningKey)
               .join(sql.KeyLink)
               .join(sql.Committee)
               .where(sql.validate_instrumented_attribute(sql.Committee.key) == 
committee_key)
           )
           result = await session.execute(statement)
           db_public_keys = result.scalars().all()
   ```
   
   #### `atr/storage/writers/keys.py` — `FoundationCommitter` (lines 196-208)
   _extension point_
   The key storage writer handles only public keys. Server-side signing would 
require extending this (or creating a new writer) to store encrypted private 
keys and perform signing operations.
   
   ```python
   class FoundationCommitter(GeneralPublic):
       def __init__(self, write: storage.Write, write_as: 
storage.WriteAsFoundationCommitter, data: db.Session):
           super().__init__(write, write_as, data)
           self.__write = write
           self.__write_as = write_as
           self.__data = data
           asf_uid = write.authorisation.asf_uid
           if asf_uid is None:
               raise storage.AccessError("Not authorized", status=403)
           self.__asf_uid = asf_uid
   
           # Specific to this module
           self.__key_block_models_cache = {}
   ```
   
   #### `atr/post/keys.py` — `PrivateKeyUploadError` (lines 53-54)
   _currently does this_
   ATR currently REJECTS private key uploads as a security measure. Server-side 
signing would require a deliberate reversal of this stance with new encrypted 
storage.
   
   ```python
   class PrivateKeyUploadError(Exception):
       pass
   ```
   
   #### `atr/post/keys.py` — `_add_key_text_resolve` (lines 238-247)
   _currently does this_
   Private key detection with immediate memory cleanup - shows current security 
stance against server-side private key storage.
   
   ```python
   async def _add_key_text_resolve(session: web.Committer, add_form: 
shared.keys.AddOpenPGPKeyForm) -> str:
       if (file := add_form.public_key_file) is None:
           key_text = add_form.public_key
           if util.contains_private_key_text(key_text):
               vars(add_form)["public_key"] = ""
               session.form_data_discard(["public_key", "public_key_file"])
               del key_text
               gc.collect()
               raise PrivateKeyUploadError
           return key_text
   ```
   
   #### `atr/storage/writers/policy.py` — `CommitteeMember` (lines 95-108)
   _extension point_
   Policy management is where a 'signing_mode' option 
(openpgp/sigstore/server-side) might be configured per project, but this is 
speculative until a design decision is made.
   
   ```python
   class CommitteeMember(CommitteeParticipant):
       def __init__(
           self,
           write: storage.Write,
           write_as: storage.WriteAsCommitteeMember,
           data: db.Session,
           committee_key: str,
       ):
           super().__init__(write, write_as, data, committee_key)
           ...
   
       async def edit_compose(self, form: shared.projects.ComposePolicyForm) -> 
None:
           project_key = form.project_key
           _, release_policy = await self.__get_or_create_policy(project_key)
   ```
   
   ### Where new code would go
   - `atr/storage/writers/signing.py` — new file
     If server-side signing is implemented, a new writer module would handle 
encrypted private key storage and signing operations.
   - `atr/tasks/checks/sigstore.py` — new file
     If Sigstore support is added, a parallel check module to signature.py 
would handle Sigstore bundle verification.
   
   ### Proposed approach
   This is a design discussion with no actionable code change at this time. The 
issue explores three directions: (1) Sigstore support alongside or replacing 
OpenPGP, (2) server-side signing where ATR generates and stores 
password-protected private keys, and (3) enhanced authentication (WebAuthn) to 
protect the signing operation. Each would require significant architectural 
work across multiple subsystems — new database models for private key or 
Sigstore metadata storage, new verification checks, policy configuration 
changes, and potentially new authentication flows.
   
   The only concrete follow-up mentioned is the tooling-releases-client issue 
#3 (client-side signing command), which is external to this repository. No 
implementation decision has been reached, and the tradeoffs remain under 
consideration. This issue should remain open as a tracking discussion for the 
signing architecture direction.
   
   ### Open questions
   - Has the ASF Security Team provided formal guidance on whether server-side 
signing with password-protected keys meets the 'automated release 
infrastructure' requirements in release policy?
   - Would Sigstore be supported only as an additional signature format 
alongside OpenPGP, or could it replace OpenPGP for some projects?
   - What is the status of the tooling-releases-client issue #3 (client-side 
signing command) — does it reduce the urgency of server-side signing?
   - Would WebAuthn enforcement be a prerequisite for server-side signing, and 
does ATR currently support WebAuthn authentication at all?
   - How would encrypted private key storage interact with the existing 
security controls that explicitly reject private key uploads 
(PrivateKeyUploadError)?
   
   _The agent reviewed this issue and is not proposing patches in this run. 
Review the existing-code citations and open questions above before deciding 
next steps._
   
   ### Files examined
   - `atr/tasks/checks/signature.py`
   - `atr/post/keys.py`
   - `atr/shared/keys.py`
   - `atr/storage/writers/keys.py`
   - `atr/get/keys.py`
   - `atr/storage/writers/policy.py`
   - `atr/post/tokens.py`
   - `atr/shared/tokens.py`
   
   ---
   *Draft from a triage agent. A human reviewer should validate before merging 
any change. The agent did not run tests or verify diffs apply.*


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to