✨ newIntroducing Fleek Machines (Early access): One-click verified and private compute
Oct 8, 2024

Unlocking Decentralized & Trustless Front-End Hosting with TEEs

Unlocking Decentralized & Trustless Front-End Hosting with TEEs

At Fleek, we’ve always been thinking and attempting to bring real decentralized front-end hosting to life. In this post, we’re excited to share how we’re planning to leverage the use of TEEs (Trusted Execution Environments), particularly Fleek Network’s Intel SGX capabilities, to power trustless DNS Name Servers. This is a key step toward realizing the dream of true decentralized front-end hosting, where domain owners have complete control over their DNS records. While there are additional steps needed to achieve the full vision of decentralized hosting, this innovation brings us much closer to that end goal— Let’s dive in.

Problem Statement

A name server can lie. Even in the centralized setup, the possibility of a DNS spoofing attack is present, however, DNSSEC has been introduced to solve this issue by constructing a chain of trust all the way from ICANN at the root of this chain, through the zones, and finally then to the individual owners of the domain. This solves the issue of tying a private key (of some signature scheme supported by DNSSEC) into a domain and using that as a way of verifying the integrity of DNS records for your domain.

Even if you don’t necessarily want a ‘decentralized frontend’, the only way you could currently trust this setup is by running your own authoritative name server and using a self-generated key. In reality, running a DNS server is far from straightforward, and most people prefer using managed name servers, such as Cloudflare.

This TEE-powered DNS Name Server project aims to solve two seemingly unrelated problems:

  1. In the case of centrally managed name servers, who is to say that your name server won’t at some point lie to some of your users? In an ideal scenario, the name server would be incapable of altering DNS records and would only be responsible for amplifying the service or product you provide at that domain.
  2. With the decentralized frontend use-case in mind, how do you provide an infrastructure where everything about the domain is owned by, let’s say, a private key of some multisig, or even a smart contract?

For the latter case, more projects in the space, notably ENS, 3DNS, and Box Domains, are enabling users to own a domain via private key, which would allow the owner of the domain to change:

  1. Their name server
  2. Their DS record (i.e DNSSEC public key)

To date, there is no way to force the name server to solely accept updates and modifications from the owner of a private key, or a smart contract controlling the name server. But this TEE powered DNS Name Server project aims to change that.


What you need to know about DNSSEC

Although DNSSEC is a complicated topic (refer to RFC 9364 for an overview), the main principle is simple.

  1. You have a private key.
  2. You give the private key to your name server.
  3. You put the public key as the ‘DS’ record.
  4. The public key would be signed by your TLD.
  5. Your name server signs the answer to its DNS queries using the private key.
  6. A DNS client trying to access your website verifies the chain of trust of a domain all the way from the root (run dig . dnskey +dnssec to see it), and once it has verified the integrity of the DS record (the public key), it checks the signature generated by the name server.

Domain Ownership

As mentioned in the problem statement, this project will only focus on the integrity of responses generated by the name server. However, by using normal TLD providers, users run the risk that the owner of the domain could always go into their registrar panel and change both the name server and the DS record, rendering our name server useless. We need to leverage other solutions prove ownership and derisk manipulation of the domain.

Two active projects in the space that address the issue at this layer are currently .Box Domains and 3DNS.


How does Fleek plan on using TEEs to help?

At Fleek, we are starting work on implementing the first authoritative name server in the world that is just like any other DNS server, albeit with one exception: when it comes to signing DNS records and keeping DNSSEC private keys around, the sensitive data is strictly run inside a secure enclave.

When the enclave is asked to generate a signature for a certain domain, inside it we will run some code to verify the authority of the person issuing this change of records. For example, a user who wishes to own their domain using a private key can do so and every time they want to change their DNS record, the enclave would verify this ‘update request’ by checking a valid signature issued by that private key.

Permission as code

Given the generality of the idea, we can not hard code the guard code for users, otherwise, we would limit the users to our decisions. For example, what would happen if a user wants to only update their DNS record with a zkProof? Or what if they want to run a lite client of another chain and mirror smart contract data as their DNS record?

If you have used Firebase, you might already be familiar with the ‘permission as code’ concept. Similarly, our plan at Fleek is to allow setting the owner of a domain to some arbitrary WASM code + metadata (referred to as the env data in this document).

This ownership code will have to comply with the interface of our spec, in technical terms it has to meet our FFI expectations. We’ve included an early draft of how this interface might look to a more technically oriented user, although given the current stage of development, there is no guarantee that this will be the final implementation — the general concept will be maintained.

extern "C" {
    /// Provided by the runtime, the WASM can call this to update
    /// the current DNS record. During a call multiple calls to
    /// this function are allowed which allows control over the
    /// DNS record table.
    ///
    /// For example, a call here could update the records only
    /// for a subdomain.
  #[link(wasm_import_module = "fdns")]
    pub fn update_record(offset: usize, size: usize);

    /// Called by the WASM code to issue a change over the owner
    /// of the entire domain. This will transfer the ownership
    /// from the current wasm to some other wasm with some arbitary
    /// arguments.
  #[link(wasm_import_module = "fdns")]
    pub fn update_owner(offset: usize, size: usize);

    /// Returns the number of bytes for the global argument given
    /// to this wasm. Global argument is the metadata bytes along
    /// the wasm code.
    ///
    /// For example, a WASM binary that implements an 'ownership
    /// by ECDSA signature' can take the public key of the owner
    /// as a global argument.
  #[link(wasm_import_module = "fdns")]
    pub fn env_size() -> usize;

    /// Copy `size` many bytes of the env bytes from the given `ofset`
    /// into the `dest`.
  #[link(wasm_import_module = "fdns")]
    pub fn env_copy(dest: usize, offset: usize, size: usize) -> usize;

    /// Returns the number of bytes.
  #[link(wasm_import_module = "fdns")]
    pub fn arg_size() -> usize;

    /// Copy `size` many bytes of the call argument bytes from the given
    /// `ofset` into the `dest`.
  #[link(wasm_import_module = "fdns")]
    pub fn arg_copy(dest: usize, offset: usize, size: usize) -> usize;

    // same sort of methods to get the current records...
}

#[derive(serde::Serialize)]
enum AppenedOrSet {
    Appened,
    Set
}

#[derive(serde::Serialize)]
enum UpdateRecord<'a> {
    Clear,
    RemoveRecords {
        record: &'a str,
        name: Option<&'a str>,
        index: Option<u16>
    },
    UpdateRecord {
        /// If =Set, this is equal to a call to Clear, followed
        /// by =Appened
        mode: AppenedOrSet,
        /// Record type e.g: 'CNAME', 'MX', 'TXT', etc
        record: &'a str,
        /// The subdomain or root domain name or wildcard.
        name: &'a str,
        /// The content of this record, has different meaning
        /// depending on the record type.
        content: &'a str,
        /// The records TTL or 'auto' by default.
        ttl: Option<&'a str>
    },
}

/// Called during the initialization to setup the initial records.
#[no_mangle]
pub extern "C" fn setup() {}

/// Called everytime an owener wants to change the records or even
/// ownership.
#[no_mangle]
pub extern "C" fn handle_update_request() {}

Bringing ENS/IPNS to the rest of the Web

Currently, projects such as eth.limo allow you to visit an ENS domain using a normal domain address — the issue here is that nothing technically prevents these projects from serving incorrect information to users. We are close with eth.limo and they are a very trusted team in the space, so nobody is worried about them being malicious, but the point remains that it’s still a risk (they are actually a perfect target user of this trustless nameserver).

Our goal is to enable eth.limo or others to create a domain that allows access to these decentralized records using a centralized domain, by verifying the state of a blockchain or other external factors, before performing any actual domain updates. The same could be applied to almost every RPC endpoint and/or gateway running in front of blockchains or other decentralized infrastructure and apps.

On-Disk Key-Value Storage + TEEs

Given that we don’t have access to file systems on a trusted level at SGX, we can use an external merkelized key-value store, and perform an inclusion proof inside the enclave every time data is read from the latest version of the database. Once the batch of updates is formed after running the mutator code, we can simply interact with the external key-value store, and get a proof that provides the next root hash (from the given set of updates on the key value of our initial root hash), resulting in the enclave producing a certificate for the root hash of its database. The next invocation to the enclave will have to provide the latest root hash + a certificate from a previous enclave execution, attesting to that root hash as an input parameter.

Extension: Secure SSL Certificate Setup Sub-Protocol

When getting an SSL certificate, a user has to perform a Domain Control Validation (DCV) to prove that they have control over the given domain name. There are usually two approaches here:

  1. HTTP-based validation: In this case, your web server has to serve some random content to prove the ownership.
  2. DNS-based validation: In this case, you’re given a random text to put in your domain’s TXT record.

We could natively support the ‘letsencrypt’ protocol for SSL certificate generation from within the enclave. When this action (the SSL cert generation) is triggered, we can accept the public key of some other entity as a parameter and, after the process is complete and the enclave has the SSL cert inside it, we can use that given public key to encrypt the cert and then provide the encrypted cert publicly, enabling the receiving entity to then decrypt the cert and use it.

What would this Secure SSL setup enable for Fleek?

Another key piece to providing real decentralized hosting! The receiving entity of the encrypted SSL cert could effectively be any other enclave, operated by anyone in any place. This way Fleek will be able to give those different kinds of hosting enclaves an SSL key safely, and then only the enclave with that SSL cert can serve valid HTTPS requests for that domain. While this concept is not currently in-scope with the name server project, it is a hugely promising innovation and natural next step. Once that is done, Fleek will have the first websites that are operated trustlessly — all the way from domain ownership (ENS, 3DNS, Box, etc) to the name server (this project) to serving HTTPS.


Conclusion

Until today, decentralized name servers felt like the typical web3 pipe dream — a brilliant concept, with no clear path to execution.

Fleek’s innovative approach to DNS Name Servers powered by Fleek Network’s Edge SGX infrastructure paves the way for more secure and decentralized front-end hosting.

By leveraging Trusted Execution Environments, we can enhance trust and transparency in DNS operations, ensuring that updates to DNS records are verifiable and controlled by the domain owner, whether a private key holder or a smart contract. While challenges like selective denial of service and maintaining update integrity remain, our ongoing work on consensus mechanisms, threshold cryptography, and network node rotation offers promising solutions. Stay tuned as we continue to build towards fully decentralized web infrastructure.

Additional Resources:

Beginners Guide to SGX- https://fleek.xyz/blog/learn/intel-sgx-beginners-guide/

Fleek Network Intel SGX Integration- https://blog.fleek.network/post/fleek-network-intel-sgx-integration/

Fleek edge SGX docs- https://fleek.xyz/docs/cli/edge-sgx/

Deploy an App on Fleek- https://fleek.xyz/docs/platform/deployments/